我有一个关于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中的错误。令人惊讶的是,尚未报告,请随时进行报告。
针对未初始化的惰性集合的操作要排队以便在初始化集合之后执行它们,并且当这些操作与数据库中的数据冲突时,Hibernate不会处理这种情况。通常这不是问题,因为此队列已在清除flush(),并且可能有冲突的更改也会在此传播到数据库flush()。但是,某些更改(例如,具有类型为generator的生成器生成的ID的实体的持久化IDENTITY,我想这是您的情况)会传播到数据库中,而不包含full flush(),在这种情况下可能会发生冲突。
flush()
IDENTITY
作为解决方法,您可以flush()在保留孩子之后进行会话:
em.persist(child); em.flush();