Hibernate将重复项插入到@OneToMany集合中

use*_*562 19 hibernate one-to-many jpa-2.0

我有一个关于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在考虑这段代码:

// 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();
Run Code Online (Sandbox Code Playgroud)

子实体被错误地插入父实体的子列表中两次.

执行以下操作之一时,代码工作正常(列表中没有重复的条目):

  • 删除mappedBy父实体中的属性
  • 对子项列表执行一些读取操作(例如,标记为取消注释的行*)

这显然是一种非常奇怪的行为.此外,当使用EclipseLink作为持久性提供程序时,代码按预期工作(没有重复).

这是一个Hibernate错误还是我错过了什么?

谢谢

axt*_*avt 27

这是Hibernate中的一个错误.令人惊讶的是,它尚未报道,请随时报告.

针对非初始化的延迟集合的操作排队,以便在初始化集合后执行它们,并且当这些操作与数据库中的数据冲突时,Hibernate不处理这种情况.通常这不是问题,因为此队列已被清除flush(),并且可能的冲突更改也会传播到数据库flush().但是,一些更改(例如,由类型的生成器生成的具有id的实体的持久化IDENTITY,我猜,这是您的情况)会在没有完整的情况下传播到数据库flush(),并且在这些情况下可能发生冲突.

作为一种解决方法,您可以flush()在持久保存孩子后进行会话:

em.persist(child); 
em.flush();
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用 hibernate 5.1.3,问题仍然可以重现 (2认同)