我有一个关于Hibernate 3.6.7和JPA 2.0的问题。
考虑以下实体(为简便起见,省略了一些getter和setter方法):
@Entity
public class Parent {
@Id
@GeneratedValue
private int id;
@OneToMany(mappedBy="parent")
private List<Child> children = new LinkedList<Child>();
@Override
public boolean equals(Object obj) {
return id == ((Parent)obj).id;
}
@Override
public int hashCode() {
return id;
}
}
@Entity
public class Child {
@Id
@GeneratedValue
private int id;
@ManyToOne
private Parent parent;
public void setParent(Parent parent) {
this.parent = parent;
}
@Override
public boolean equals(Object obj) {
return id == ((Child)obj).id;
}
@Override
public int hashCode() {
return id;
}
}
现在考虑这段代码:
// persist parent entity in a transaction
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Parent parent = new Parent();
em.persist(parent);
int id = parent.getId();
em.getTransaction().commit();
em.close();
// relate and persist child entity in a new transaction
em = emf.createEntityManager();
em.getTransaction().begin();
parent = em.find(Parent.class, id);
// *: parent.getChildren().size();
Child child = new Child();
child.setParent(parent);
parent.getChildren().add(child);
em.persist(child);
System.out.println(parent.getChildren()); // -> [Child@1, Child@1]
em.getTransaction().commit();
em.close();
子实体被错误地两次插入到父实体的子列表中。
执行以下操作之一时,代码可以正常工作(列表中没有重复的条目):
删除父实体中的
mappedBy
属性在子级列表上执行一些读取操作(例如,用
*
标记的取消注释行)这显然是非常奇怪的行为。另外,当使用EclipseLink作为持久性提供程序时,代码按预期方式工作(没有重复)。
这是Hibernate的错误,还是我缺少什么?
谢谢
最佳答案
这是Hibernate中的错误。令人惊讶的是,feel free to report it尚未报告。
对未初始化的惰性集合的操作要排队以便在初始化集合之后执行它们,并且当这些操作与数据库中的数据冲突时,Hibernate不会处理这种情况。通常这不是问题,因为此队列在flush()
时清除,并且可能发生的冲突更改也在flush()
时传播到数据库。但是,某些更改(例如,持久化具有类型为IDENTITY
的生成器生成的ID的实体,我想这是您的情况)会传播到没有完整的flush()
的数据库中,在这些情况下可能会发生冲突。
作为解决方法,您可以在保留子项之后flush()
会话:
em.persist(child);
em.flush();
关于hibernate - Hibernate将重复项插入@OneToMany集合中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7903800/