2010-02-16 95 views
5

我有兩個實體(父和子)之間的父子關係。從集合中刪除一個項目(NHibernate)

我父母映射如下:

<class name="Parent" table="Parents"> 
    ... 
    <bag name="Children" cascade="all"> 
     <key column="ParentID"></key> 
     <one-to-many class="Child"></one-to-many> 
    </bag> 
</class> 

我想執行如下:

someParent.Children.Remove(someChild); 

子類有另一個父類的引用,類型。的關係看起來像

relation diagram

注:我爲無鏈接的URL上面道歉,我似乎無法讓過去使用標記

在URL字符串中的星號由於這種關係,當調用上述代碼而不是DELETE查詢時,會生成一個UPDATE查詢,該查詢從Child表中刪除ParentID(設置爲空)。

當從Parent.Children集合中刪除時,是否可以強制NHibernate完全刪除子記錄?

UPDATE

@斯賓塞的解決方案

非常具有吸引力的解決方案,因爲這是不能夠在未來的類實現。但是,由於存儲庫模式中的會話處理方式(在我的具體情況下),這幾乎是不可能的,因爲我們必須根據應用程序傳遞會話類型(CallSessionContext/WebSessionContext)。

@傑米的解決方案

簡單快速實施,但我已經打了另一個路障。我的子實體如下所示: entity object

當使用新方法時,NHibernate生成一個更新語句,將TypeID和ParentID設置爲null,而不是單個刪除徹底。如果我在執行過程中遺漏了某些東西,請告訴我,因爲這種方法很容易實現。

@The One-Shot-Delete solution described here,概述瞭解引用集合強制單個刪除的想法。然而,與上述結果相同,會發布更新聲明。

//Instantiate new collection and add persisted items 
List<Child> children = new List<Child>(); 
children.AddRange(parent.Children); 

//Find and remove requested items from new collection 
var childrenToRemove = children 
    .Where(c => c.Type.TypeID == 1) 
    .ToList(); 

foreach (var c in childrenToRemove) { children.Remove(m); } 
parent.Children = null; 

//Set persisted collection to new list 
parent.Children = Children; 

解決方案

花了一點挖,但傑米的解決方案來通過與一些額外的修改。對於未來的讀者,根據我的類模型上面:

類型映射 - 逆=真正的,級聯=所有

父映射 - 逆=真正的,級聯=全刪除,孤兒

刪除方法爲在Jamie的解決方案中描述。這確實會爲每個孤兒項目生成一條刪除語句,所以有可能在將來進行調優,但最終結果是成功的。

回答

1

而是露出IList<Child>,通過一種方法控制訪問集合:

RemoveChild(Child child) 
{ 
    Children.Remove(child); 
    child.Parent = null; 
    child.Type.RemoveChild(child); 
} 

Type.RemoveChild看起來相似,但你必須要小心,不要把它變成一個無限循環調用對方的RemoveChild方法。

0

我不認爲這是完全可能的,因爲Hibernate無法知道記錄是否被孤立。它可以檢查是否有其他類與子類相關,但是假設它知道整個DB結構可能不是這種情況。

然而,你並不完全沒有運氣。通過將IList接口與您創建的自定義ICascadeDeleteChild接口結合使用,您可以提出一個相當無縫的解決方案。這是基本步驟。

  1. 創建一個讓IList和IList爲<>並稱之爲CascadeDeleteList或類似行的類。
  2. 在這個類中創建一個私有的.Net列表,並簡單地將對這個列表的各種方法調用代理。
  3. 創建一個名爲ICascadeDeleteChild的接口並給它一個方法Delete()
  4. 在您的CascadeDeleteList的Delete方法下,檢查要刪除的對象的類型。如果它是ICascadeDeleteChild類型,那麼就調用它的Delete方法。
  5. 更改您的Child類以實現ICascadeDeleteChild接口。

我知道這似乎是一種痛苦,但一旦完成這些接口應該是簡單的端口。

+0

我相信這可能引發了我走上正確的道路,路障是:將其設置爲存儲庫模式(即,在這種情況下,子刪除方法將調用其自己的存儲庫方法),並且能夠使用這與不同的會話上下文(即,CallSessionContext vs WebSessionContext) – 2010-02-16 23:06:42