Hibernate将重复项插入到@OneToMany集合中 [英] Hibernate inserts duplicates into a @OneToMany collection

查看:115
本文介绍了Hibernate将重复项插入到@OneToMany集合中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于Hibernate 3.6.7和JPA 2.0的问题。



考虑以下实体(为简洁起见,省略了一些getter和setter):

  @Entity 
public class Parent {
@Id
@GeneratedValue
private int id;

@OneToMany(mappedBy =parent)
私人列表< 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
私人父母;

public void setParent(父母){
this.parent = parent;


@Override
public boolean equals(Object obj){
return id ==((Child)obj).id;
}

@Override
public int hashCode(){
return id;


现在考虑这段代码:

  // //在事务中坚持父实体

EntityManager em = emf.createEntityManager();
em.getTransaction()。begin();

父母=新父母();
em.persist(parent);
int id = parent.getId();

em.getTransaction()。commit();
em.close();

//在新事务中关联并持久化子实体

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()时可能冲突的更改传播到数据库。 code>以及。但是,有些更改(例如,持有具有由 IDENTITY 类型的生成器生成的id的实体,我想这是您的情况)会传播到数据库而没有完整的 flush(),在这种情况下可能发生冲突。



作为一种解决方法,您可以 flush )继续孩子之后的会话:

  em.persist(child); 
em.flush();


I have a question concerning Hibernate 3.6.7 and JPA 2.0.

Consider following entities (some getters and setters are omitted for brevity):

@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;
    }
}

Now consider this piece of code:

// 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();

The child entity is wrongly being inserted twice into the list of children of the parent entity.

When doing one of the following, the code works fine (no duplicate entries in the list):

  • remove the mappedBy attribute in the parent entity
  • perform some read operation on the list of children (e.g. uncomment line marked by *)

This is obviously a very weird behavior. Also, when using EclipseLink as the persistence provider, the code works just as expected (no duplicates).

Is this a Hibernate bug or am I missing something?

Thanks

解决方案

It's a bug in Hibernate. Surprisingly, it's not reported yet, feel free to report it.

Operations against non-initialized lazy collections are queued in order to execute them after collection is initialized, and Hibernate doesn't handle the situation when these operations conflict with the data from the database. Usually it's not a problem, because this queue is cleared upon flush(), and possible conflicting changes are propagated to the database upon flush() as well. However, some changes (such as persisting of entities with ids generated by generator of type IDENTITY, I guess, it's your case) are propagated to the database without the full flush(), and in these cases conflicts are possible.

As a workaround you can flush() the session after persisting the child:

em.persist(child); 
em.flush();

这篇关于Hibernate将重复项插入到@OneToMany集合中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆