2011-09-30 69 views
2

我的問題是非常相似,這一個(這是不是真的回答):Nhibernate: distinct results in second level Collection加載多層次的收藏NHibernate的

我有這樣的對象模型:

class EntityA 
    { 
     ... 
     IList<EntityB> BList { get; protected set; } 
     ... 
    } 

    class EntityB 
    { 
     ... does NOT reference its parent EntityA... 
     IList<EntityC> CList { get; protected set; } 
    } 

他們是一一對多關係。 EntityB和C do 不是有一個對它的父對象的對象引用。

我想通過執行類似下面的三個SQL查詢,以避免笛卡兒完全加載集合聯接:

SELECT id, ... FROM EntityA; 
SELECT id, idA, ... FROM EntityB; 
SELECT id, idB, ... FROM EntityC; 

隨即,DAL具有的所有信息填寫正確的對象。但是由於EntityB不知道其父母是誰,所以作爲nHibernate負責正確填寫收集。

可以這樣做嗎?


可以做到這一點的解決方法與笛卡爾乘積,但它需要修改我的模型,以提供一個集合setter和有資格爲在我腦海中的技術問題與DAL補丁。

 ICriteria criteria = session.CreateCriteria<EntityA>() 
         .SetFetchMode("BList", FetchMode.Join) 
         .SetFetchMode("BList.CList", FetchMode.Join) 
         .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

    IList<EntityA> listA = criteria.List<EntityA>(); 

    foreach (EntityA objA in listA) { 
     objA.BList = objA.BList.Distinct().ToList(); 
     foreach (EntityB objB in objB.BList) { 
      objB.CList = objB.CList.Distinct().ToList(); 
     } 
    } 
+0

這不會是笛卡爾產品。它只是很多複製的數據。對於每個額外的EntityC EntityB複製實體B,由於ResultTransformer,這將是很好的。你可以通過將該集合作爲ISet <>來避免那些被騙的EntityB。儘管如此,它仍然有很多額外的數據。 – dotjoe

+0

事實上,你說的不是笛卡兒的產品,因爲它不是N對N,對此抱歉。 ISet是無序的,所以對於我的方案來說這不是一個真正的選擇。 – dstj

回答

4

你有沒有嘗試過這樣的語法:

var entities = session.QueryOver<EntityA>().Where(...).List(); 
var entityIds = entities.Select(e => e.Id).ToArray(); 
session.QueryOver<EntityA>() 
    .WhereRestrictionOn(a => a.Id) 
    .IsIn(entityIds) 
    .Fetch(e => e.BList).Eager 
    .List(); 

var bEntityIds = entities 
    .SelectMany(e => e.BList) 
    .Select(b => b.Id) 
    .ToArray(); 

session.QueryOver<EntityB>() 
    .WhereRestrictionOn(b => b.Id) 
    .IsIn(bEntityIds).Fetch(e => e.CList).Eager 
    .List(); 

這應該解僱你提到三個選擇。看起來似乎有些複雜,但它利用了會話的第一級緩存,這可以確保第一個集合中的所有實體在執行時都會使用加載的集合進行更新。

此外,您不支付任何複雜的查詢邏輯的懲罰,您可能有第二個和第三個查詢的邏輯。數據庫應該爲第二個查詢使用主索引(甚至可能根據您的設置進行聚簇)以及用於超低成本查詢的聯接的外鍵。

+0

謝謝地精!我是NHibernate的新手,所以我從來不會想到這個語法是我自己的!使用探查器,我現在只有3個查詢。它們使用WHERE IN子句,但始終在主鍵和外鍵索引上,因此應該很快。 在你的代碼的最後一行有一個小的錯誤,這是結束了工作: 'session.QueryOver ().WhereRestrictionOn(B => b.Id).IsIn(bEntityIds).Fetch(E => e.CList).Eager.List();' – dstj

+0

沒問題:-)是的 - 這是兩種不同解決方案的不好組合......我會更新:-)如果你真的對NHibernate的複雜方式感興趣,我強烈建議你看看ayende.com的博客檔案。請務必首先查看最新的帖子,因爲他在之前的帖子中有一些過時的信息。 – Goblin