[英]Can't get hibernate to delete children instances via cascade, that were removed from a one-to-many relation
這里的小問題:
我有兩個實體類
class Parent {
Set<Child> children;
}
class Child {
SomethingElse reference;
}
現在,映射實質上是:
<class name="Parent" lazy="false">
<set name="children" lazy="false" cascade="all-delete-orphan">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
(我在這里省略了ID映射和字段,我使用常規生成的ID)
我基本上需要保持一個干凈的數據庫,就像我從父級列表中刪除元素然后提交父級時一樣,需要刪除相應刪除的子級數據庫條目。 子實例引用了我以后需要刪除的其他實體,因此,如果子實例保留在數據庫中,我將無法刪除那些引用的對象。
到目前為止,我發現的結果是:如果我將Hibernate的PersistentCollection包裝器放置在適當的位置,那么我在下面嘗試的任何事情都應該起作用。 問題是,我的數據庫對象來自幾層框架,其中包括一個UI框架(使用Bean屬性抽象來調用setter),以及一個網絡通信層(用於來回克隆和序列化對象)。 這兩個層都在內部替換了集合實例,因此刪除了這些PersistentCollection包裝器。 重寫這些文件將不這樣做。
就是說,我嘗試了8種方法,但均無效:
1)將關系配置為cascade =“ all”,使用session.update(parent)。
2)將關系配置為cascade =“ all-delete-orphan”,使用session.update(parent)。
3)將關系配置為cascade =“ all”,並使用session.merge(parent)
所有這些導致休眠執行“ UPDATE CHILD SET parent.id = null,WHERE parent.id = ...”。 重新加載父實例時,這成功地從父列表中刪除了子對象,但是子實例保留在數據庫中,並阻止了我刪除其他引用的實體。
4-6)使用配置1-3,同時將父鍵列定義為非null
這導致休眠狀態不執行任何操作。 我在另一篇文章中讀到,將鍵列設置為非空將導致刪除。 聽起來是可行的,因為更新為null不再是一個選項,但是不起作用。 如果我從集合中刪除子代,則提交更改並從數據庫中重新加載實例,子代會重新出現。
7 + 8)可為空或不可為空的父鍵無關緊要,但是將關系配置為cascade = all-delete-orphans並使用session.merge(parent)
由於刪除了PersistentCollection包裝器,這導致休眠狀態拋出異常“擁有實體實例不再引用具有Cascade =“ all-delete-orphan”的集合”。
為了解決我的問題,我唯一需要的是休眠以選項1-3的形式執行查詢,該查詢作為DELETE而不是UPDATE。 我希望我找不到以沒有PersistentCollection包裝器的方式刪除這些映射的方式來配置映射的選項,但是對我來說,目前看來好像沒有這樣的選項。 有人知道是否有配置此方法的方法嗎?
/ edit:為了澄清,我想發生的事的例子:
Parent parent = new Parent();
parent.setChildren(new HashSet<Child>(Arrays.asList(new Child()))));
session.insert(parent)
// this correctly results in (approximately):
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...
parent.setChildren(new HashSet<Child>()); // using .clear() is not an option.
session.update(parent);
// this results in:
// SQL> UPDATE CHILD set parent_id = null WHERE parent_id = ${id.of.parent}
// but i need this to result in:
// SQL> DELETE FROM CHILD WHERE parent_id = ${id.of.parent}
好吧,我現在顯然已經解決了。 問題是我沒有分配空集,而是空值。 顯然,在session.merge(updated)的情況下,休眠模式突然將空集合與空集合區分開。 在為屬性分配空集合實例的情況下,使用cascade =“ all-delete-orphan”和.merge()可以,分配null而不是空集合實例會引發上述異常。 無論鍵列的可空性約束如何,都相同。
我不知道這是否被視為故意行為,因為通常空值的行為與空集合的行為相同。 我看看是否可以找到更多有關此的信息,然后提出錯誤報告。
這並不能完全回答您的問題,但是希望對您有所幫助。
首先,我建議你看看這個解釋 ,以及這一個 。
現在,您自己說了子對象沒有引用父對象,這是一種單向關系。 我不知道您想出了哪種映射,但這是:
Parent parent = new Parent();
parent.setChildren(Collections.singleton(new Child())));
session.save(parent);
// this correctly results in:
// SQL> INSERT INTO PARENT ...
// SQL> INSERT INTO CHILD ...
僅在以下情況下才有可能工作:
cascade
組中的映射被啟用 (如cascade="all"
,否則Hibernate會抱怨新的未保存的瞬態的實例Child
對象) 另外,Hibernate除了在注釋中提到的這兩個插入之外,還將生成一個SQL UPDATE
(您可以看到的內容實際上是在我給您的鏈接中進行了說明)。
希望你能從中得到一些東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.