2017-03-22 53 views
12

我试图做这样的休眠实体A的副本:如何使休眠集合的副本与级联=“全删除,孤儿”

A a = (A) session.get(A.class, id); 
session.evict(a); 
a.setId(null); 
session.save(a); 

然而,这并不工作,我得到以下expetion:

org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.test.A.B 

它的安全承担这个错误是因为我已经在实体中的定义乙实体的集合:

<list name="B" table="B" lazy="false" cascade="all,delete-orphan"> 
    <key column="A_ID" not-null="true"/> 
    <index column="X"/>    
    <one-to-many class="com.test.B"/> 
</list> 

如何制作实体A的副本,包括它的实体B的集合,而不休眠是否不满意?

+0

什么是你的休眠版本? –

+0

休眠版本是3。2 – user1985273

+1

请澄清:你是否想在复制实体的集合中保留*相同的*元素,或者是否想要复制集合中的元素? – Andremoniy

回答

1

有没有自动的方式来复制这样的对象。通常,复制的对象可能与其他对象进一步关联,这些对象与其他对象进一步关联等,因此您最终可能会复制大部分数据库。你用于复制的任何工具都需要知道对象图中停止拷贝的地方,不要拷贝什么(根据Hibernate实体,它们是id,版本列和类似的),等等。

然而,您可以利用框架如Dozer来避免大部分需要手动编写的样板代码。

关于收集重新分配问题,您不能将B实例的相同集合分配给两个不同的A,因为它在逻辑上会成为many-to-many关联。这也是您需要手动处理的事情,因为它特定于您的业务用例。

此外,请确保您不要在其他人的实体实例中重复使用同一个集合代理,因为Hibernate将它们与其原始父母绑定在内部 - 总是在新实例中创建新集合(可能包含或不包含相同的元素)。

1

如果要复制现有实体 - 修改它并将其另存为新实体,则需要深度复制该对象。您可以通过序列化对对象执行深层副本,然后对该对象进行反序列化。

public Object deepCopy(Object input) { 

    Object output = null; 
    try { 
     // Writes the object 
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
     ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); 
     objectOutputStream.writeObject(input); 

     // Reads the object 
     ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
     ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 
     output = objectInputStream.readObject(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return output; 
} 
3

我以前在我的项目中遇到过同样的问题。

对我来说,它有效,将list-entries的ID设置为null。

// make copy a of aOriginal by using serialisation clone 
a.setId(null); 
for (B b : a.getBs()) { 
    b.setId(null); 
} 
session.save(a); 

对于克隆本身,我使用Apache SerializationUtils clone

原因是,hibernate试图“复用”已经存在的“复制”实体的列表条目。但是这个已经存在的列表条目被链接到一个原始实体。所以它试图在实体中“改变”列表本身,因为实体改变了。但是,如果用“删除孤儿”(只能修改列表中的条目,而不是列表本身)注释,则不能更改列表。所以抛出异常。

如果我将list-entry-IDs设置为null,它们也会被插入newley。对象层次结构(而不​​是仅主要实体)被复制。所以这个豁免不再被抛出。