2017-03-22 76 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。對象層次結構(而不​​是僅主要實體)被複制。所以這個豁免不再被拋出。