Hibernate - 已经持久化的孩子的“分离实体传递给持久化”错误

Posted

技术标签:

【中文标题】Hibernate - 已经持久化的孩子的“分离实体传递给持久化”错误【英文标题】:Hibernate - "detached entity passed to persist" error for already persisted child 【发布时间】:2013-06-03 22:27:24 【问题描述】:

我有一个实体,它已经被持久化并且想要将它添加到新生成的父实体(尚未持久化)。如果我尝试坚持父然后,我得到错误“分离的实体传递给坚持:model.Child”。我想我必须以某种方式为孩子调用“entityManager.merge()”而不是“entityManager.persist()”。但是我没有明确地调用persist。这由“cascade = CascadeType.ALL”注释处理。如果实体已经存在,我可以告诉休眠以某种方式在这里进行合并吗?

顺便说一句:如果我先持久化父级,然后添加子级,然后再次持久化父级 -> 它可以工作(但使我的应用程序逻辑更加复杂)。

这是我的代码:

public class App 

    @Test
    public void test()
    

        // I have a child object (in the real app 
        //this is a user object and already persisted
        Child child = new Child();
        HibernateHelper.persist(child);

        Parent parent = new Parent();

        parent.addChildren(child);
        // throws the exception "detached entity passed to persist: model.Child"
        HibernateHelper.persist(parent);

        Parent newParent = HibernateHelper.find(Parent.class, parent.getId());
        assertEquals(1,  newParent.getChildren().size());

    

我的“子”实体:

@Entity
@Table(name = "child")
public class Child 

    public Child()

    private Long id;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    private Parent parent;

    @ManyToOne
    @JoinColumn
    public Parent getParent() 
        return parent;
    

    public void setParent(Parent parent) 
        this.parent = parent;
    




我的“父”实体:

@Entity
@Table(name="parent")
public class Parent 

    public Parent()

    private Long id;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    private Set<Child> children = new HashSet<Child>();

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    public Set<Child> getChildren() 
        return children;
    
    public void setChildren(Set<Child> children) 
        this.children = children;
    
    public void addChildren(Child child)
        children.add(child);
        child.setParent(this);
    

persist 辅助方法(对于孩子来说看起来一样)

public static void persist(Parent entity)

    EntityManager entityManager = null;
    try 
        entityManager = beginTransaction();

        if(entity.getId()!=null)
            entityManager.merge(entity);
        else
            entityManager.persist(entity);
        
        entityManager.getTransaction().commit();
     catch (Exception e) 
        System.out.println(e);
        return;
    finally
        if(entityManager != null)
            entityManager.close();
    

【问题讨论】:

【参考方案1】:

一个选项是始终使用 EntityManager.merge。如果传递了新实体,则将其持久化,如果传递分离的实体,则将其合并到当前持久化上下文中。

【讨论】:

这种方法有什么缺点吗? merge 返回托管实例,persist 将参数转换为托管实例。调用persist方法后对对象的进一步更改不会反映到数据库中,但是在调用合并时,您已经在当前实现中拥有了这一点

以上是关于Hibernate - 已经持久化的孩子的“分离实体传递给持久化”错误的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 持久化对象和一级缓存

Hibernate 几种对象状态

Hibernate 中对象的三种状态及其转化

Java对象在Hibernate持久化层的状态

Java对象在Hibernate持久化层的状态

Hibernate介绍