簡體   English   中英

無法休眠通過級聯刪除子實例,這些實例已從一對多關系中刪除

[英]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而不是空集合實例會引發上述異常。 無論鍵列的可空性約束如何,都相同。

我不知道這是否被視為故意行為,因為通常空值的行為與空集合的行為相同。 我看看是否可以找到更多有關此的信息,然后提出錯誤報告。

更新:問題在https://hibernate.atlassian.net/browse/HHH-7726

這並不能完全回答您的問題,但是希望對您有所幫助。
首先,我建議你看看這個解釋 ,以及這一個

現在,您自己說了子對象沒有引用父對象,這是一種單向關系。 我不知道您想出了哪種映射,但這是:

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對象)
  • parent_id列是可為空的 (否則,Hibernate會期望您預置此字段,只有在您已映射關系的另一面時才可能設置)

另外,Hibernate除了在注釋中提到的這兩個插入之外,還將生成一個SQL UPDATE (您可以看到的內容實際上是在我給您的鏈接中進行了說明)。

希望你能從中得到一些東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM