JPA持久存在来自ManyToMany关系的对象

时间:2011-10-01 06:12:11

标签: java jpa jpql

我在类A和类B之间有@ManyToMany关系:类A引用类B实例的集合,并且此关系配置为CascadeType.ALL。因此,当A与实体管理器一起持久化时,A引用的B实例也会被持久化。

A和B都有一个使用GenerationType.IDENTITY策略声明的ID,以使用MySQL数据库中的auto_inc。

问题是:

  1. 我创建了一个新的
  2. 我使用JPQL
  3. 从entityManager加载一些现有的B对象
  4. 我将B对象添加到A的Bs集合
  5. => JPA尝试保留B对象,尽管它们已经被持久化(它们刚被加载)。

    我不明白为什么它会再次尝试保留它们,它们已经正确加载,并且它们的自动生成的id也已经很好地加载了。

    ManyToMany声明:

    @ManyToMany(cascade={CascadeType.ALL})
    @JoinTable(name = "ENTRY_ENTITIES", joinColumns =
    @JoinColumn(name = "ENTRY", referencedColumnName = "ID"),
    inverseJoinColumns = @JoinColumn(name = "ENTITY", referencedColumnName = "ID"))
    private List<Entity> entities;
    

    从数据库加载现有对象的查询:

    T result = (T) entityManager.createQuery("SELECT x FROM " + entityName + " x WHERE x.externalId='" + externalId + "'").getSingleResult();
    

    坚持:

    UserTransaction transaction = getTransaction();
    try {
        transaction.begin();
        entityManager.persist(entity);
        transaction.commit();
    } catch (Throwable t) {
        Logger.getLogger(JpaDao.class.getName()).log(Level.SEVERE, null, t);
    }
    

    非常感谢你的帮助!

2 个答案:

答案 0 :(得分:2)

我不完全确定这是您问题的原因,但您应该将整个内容包含在事务中。不只是持久性部分:

start transaction
load B from DB
create new A
add B to A
commit transaction

正如我在评论中所说,您还有其他设计和编码问题:

  • 在ManyToXxx关联中,CascadeType.ALL出错。删除A时,不希望删除A的所有B,因为其他As引用了这些B.这将导致约束违规(在最好的情况下)或不一致的数据库(在最坏的情况下,如果没有定义约束)
  • 不要在查询中使用字符串连接。使用参数化查询。这样可以避免引用问题和注入攻击:SELECT x FROM A x WHERE x.externalId = :externalId

答案 1 :(得分:1)

这些B实体可能是您将其添加到A的时间点的另一个持久性上下文的一部分。您是否尝试在启动事务后在B实体上使用merge operation之前< / strong>将它们添加到您的A实体。