2010-01-14 37 views
13

我有這些實體休眠 - 清除收集與全刪除,孤兒,然後添加到它會導致ConstraintViolationException

class Foo{ 
    Set<Bar> bars; 
} 

class Bar{ 
    Foo parent; 
    String localIdentifier; 
} 

有了這個映射(抱歉,沒有註釋,我老土):

<class name="Foo"> 
    ... 
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true"> 
     <key>...</key> 
     <one-to-many class="Bar"/> 
    </set> 
</class> 


<class name="Bar"> 
    ... 
    <property name="localIdentifier" column="local_identifier"/> 
    <many-to-one name="parent" column="parent_id" /> 
</class> 

我也有2列的唯一約束:local_identifierparent_id和(未在每個獨特的約束,但同時含有單個唯一約束,例如,沒有2行具有相同父和相同localIdentifier被允許)

alter table bar add constraint unique_bar unique (parent_id, local_identifier) 

而這種代碼使用它們:

//foo is persistent, foo id = 1 
Bars bars = foo.getBars(); 
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"] 
Bar newBar = new Bar(); 
newBar.setParent(foo); 
newBar.setLocalIdentifier("a"); 
bars.add(newBar); 

現在,出於某種原因,Hibernate並不在他們被調用的順序執行的東西。它不執行clear()add()(插入)之前(刪除),但反過來,它首先試圖插入,得到一個ConstraintViolationException

我知道加入bars.clear();後有點session.flush(),可以解決這個問題,但在這種情況下, ,我無法以不醜的方式訪問該會話。

那麼沖洗是唯一的解決方案?或者是否存在尊重操作順序的Hibernate版本?

更新: 順便說一句,提領該集合將導致HibernateException的從https://www.hibernate.org/117.html#A3

我得到HibernateException的:不要取消引用 收集與 級聯=「全刪除-orphan「這個 會發生,如果你加載一個帶有級聯的對象 cascade =」all-delete-orphan「 collection,然後刪除 對集合的引用。不要 取代此集合,請使用clear() ,以便孤兒刪除算法可以 檢測到您的更改。

+2

我覺得沖洗是這裏唯一的選擇 – ruchirhhi 2010-01-14 15:53:15

+0

相對[Hibernate Forum topic](https://forum.hibernate.org/viewtopic.php?t=934483)。 – 2011-09-05 16:43:53

回答

8

我想有沒有替代沖洗

here

休眠違反唯一約束!

休眠不像 聰明與獨特的約束,因爲它 是與外鍵。有時你可能需要提供一些提示。

可能 發生違反唯一約束兩個對象是否更新均爲 ,一個是「釋放」的值 ,另一種是「獲得」相同 值。在更新 第一個對象之後和更新 秒之後,手動解決方案是flush() 會話。

(這種問題在 實踐中很少發生。)

1

如果您想避免在此刷新會話,請嘗試替換整個列表(new List<Bar>()而不是Clear())。在添加新內容之前,Hibernate實際上應該刪除一個鏡頭中的所有項目。只是一個嘗試,不知道它是否工作。

+1

謝謝,但不是:https://www.hibernate.org/117.html#A3我會更新問題 – 2010-01-14 16:39:11

1

如果您使用的是Oracle,你也可以使用延遲約束推遲的約束檢查,直到事務被提交。不知道這是否被其他數據庫支持。