2014-10-08 117 views
1

我使用SINGLE_TABLE繼承策略在Java中的Hibernate,這裏是設置:似乎無法擺脫NonUniqueObjectException

Class A 

@Cascade(CascadeType.DELETE_ORPHAN, CascadeType.ALL) 
List<B> Bs; 

B具有延伸B.巴有一個額外的領域sublcass巴是b不具有。我這樣做的原因是隻有Ba對象(這個數量少得多)應該關心這個額外的字段,並且我想避免在每個B對象上的開銷。

在保存過程中,我們的設置方式是,我們必須更新前B對象字段(而不僅僅是更改引用)。所以我們不能做Bs列表=變更Bs列表,我們必須通過主鍵找到每個B並更新字段,所以像B.fields = changedB.fields

發生此異常的時間是在保存過程中,當一個前B對象需要被保存爲帶有額外字段的Ba時。相反的方向(將一個前Ba對象保存到B)很好,我可以將該額外字段設置爲null或拋棄。但我似乎無法找到將B對象變成Ba的方法。

我已經試過

  • 從列表中刪除了B和添加鋇保存之前,也就是當我得到這個例外。
  • 我甚至嘗試將所有從B到B的字段交換成需要變成B和副verca的字段,但那也不起作用,我得到了一個異常,因爲我改變了這些對象的Pk 。

回答

1

Session flush the DML operation order是:

  • 插入
  • 更新
  • 集合元素的缺失集合元素
  • 插入刪除

因此,即使刪除了元素並添加了新元素,插入也會在刪除之前運行,因此會拋出違反約束的異常。

要使其工作,你需要手動刷新,刪除後添加新元素之前回到孩子們集合:

a.removeChild(b); 
session.flush(); 
a.addChild(ba); 

刪除/的addChild是公用事業設置雙向兩側如果在你的領域模型中是這種情況的話。

+0

不幸的是,我沒有在我這樣做的代碼部分的會話上下文。我這樣做的地方很簡單,將收集的新列表設置爲舊列表,以便hibernate可以保存新列表。那麼沒有其他辦法可以將B對象設置爲Ba(帶有額外的字段)嗎?我的意思是我只需要爲我知道存在於數據庫(和子類)中的字段添加額外的值,而不是在對象本身上。 – James 2014-10-08 20:31:26

+0

重新分配新集合將刪除所有子項並添加新對象。這不是有效的,在你的情況下也是無效的。它導致先插入並在稍後刪除。所以你需要推動你有Session的邏輯。 – 2014-10-09 04:21:13