2011-02-23 60 views
3

我有一個實體,它具有軟刪除的子對象。當我打電話給父母時,我希望它能夠檢索未被軟刪除的子對象。我所有的實體都有一個基類,其中保存了id,audit,soft delete字段。Nhibernate過濾器不一致地應用於子集合

爲了實現這一點,我創建了2個事件監聽器和1個過濾器,一個事件監聽器將級聯軟刪除(如果有必要),另一個將預過濾器應用於預加載。

public class NonDeletedFilter : FilterDefinition 
{ 
    public static string FilterName = "NonDeletedFilter"; 
    public NonDeletedFilter() 
    { 
     WithName(FilterName).WithCondition("IsDeleted = 0"); 
    } 
} 

public class ParentMap : IAutoMappingOverride<Parent> 
{ 
    public void Override(FluentNHibernate.Automapping.AutoMapping<Parent> mapping) 
    { 
     mapping.HasMany(x => x.Children).Fetch.Join() 
       .Inverse() 
       .Cascade.AllDeleteOrphan() 
       .ApplyFilter(NonDeletedFilter.FilterName); 
    } 
} 

public class PreLoadEventListener : DefaultPreLoadEventListener 
{ 
    public override void OnPreLoad(NHibernate.Event.PreLoadEvent preloadEvent) 
    { 
     preloadEvent.Session.EnableFilter(NonDeletedFilter.FilterName); 
     base.OnPreLoad(preloadEvent); 
    } 
} 

這是問題,它是最糟糕的一種:有時它是有效的。在我的測試用例中,它完美地創建了SQL。它選擇父項,爲子項留下一個左外連接,並確保子項被刪除= false。在我的應用程序中,它沒有,它只是在沒有檢查的情況下進行連接。它適用於具有相同映射覆蓋的單獨父/子關係。

配置從相同的映射構建,具有相同的過濾器和事件偵聽器。我能看到的唯一區別是我的測試使用內存中的sqlite數據庫,其中數據庫是基於映射創建的,然後執行初始化sql以預填充數據庫。但它是從實際數據填充的,我找不到任何差異。

在這一點上,我想我的問題是我應該看什麼?

這是我的想法。表格不正確?他們看起來很好。映射是否遺漏了某些東西?他們看起來一樣。過濾器沒有被應用?那是另一回事了。過濾器是否工作?這是另一回事。

也許我看過這麼多的代碼,我看不到問題。任何人都可以在哪裏集中我的努力?

+0

一般來說,除非你有一個非常非常令人信服的商業理由讓你實時數據混合軟刪除的數據,它只是導致混亂。 http://ayende.com/Blog/archive/2009/08/30/avoid-soft-deletes.aspx – Ryan 2011-02-23 21:49:19

+1

我知道這只是時間問題。任何時候都會提到軟刪除,總是有人指出它應該被避免。在開發者手中很少有這樣的選擇。我會說,軟刪除是一種功能,而不是一個回落的解決方案審覈或歸檔,這是重要的,但常常被忽視的注意,ayende提到。所以,如果你理解了軟刪除要求,或在您的要求是不靈活的,不要害怕在此發佈的解決方案。 – Boyd 2011-02-24 15:29:16

+0

評論不一定是針對你的,而是未來可能能夠做出自己的架構決策的人遇到這種情況。 – Ryan 2011-03-03 06:57:12

回答

0

經過幾個令人難以置信的小時,這個問題終於顯露出來了。我有一個基礎庫調用來將讀取語句應用到屬性。對於被破壞的類,存儲庫獲取相同的屬性,從而覆蓋在地圖類中設置的過濾器。是的,我一直在研究它太久以至於沒有注意到其中的差異。另一組人員正在研究它,並注意到工作人員正在通過儲存庫採取不同的途徑。所以,+1對結對編程。

而對於人誰是想知道爲什麼預緊事件偵聽器不能正常工作,請確保您在創建自定義標準,不重寫的數據抓取策略。

我應該知道更好,因爲這被用在其他地方繞過過濾器,並顯式返回所有對象,無論軟刪除。

以下是存儲庫中已完成的示例。

public override Parent Get(id) 
{ 
    Session.CreateCriteria<Parent>() 
      .Fetch<Parent>(x => x.Children) 
} 

public static ICriteria Fetch<T>(this ICriteria criteria, params Expression<Func<T, object>>[] fetch) 
{ 
    foreach (Expression<Func<T, object>> expression in fetch) 
     criteria.SetFetchMode(expression, FetchMode.Join); 

    return criteria; 
} 

包括的是一個擴展方法創建自定義標準時清理的代碼。