2011-05-31 14 views
5

我有一個父對象,其中包含一個元素的子集合,子集合包含一個包含3個元素的「grandchild」集合。NHibernate ThenFetchMany檢索重複的子代

我從使用NHibernate數據庫加載父對象如下

Parent parentObject = session.Query<Parent>() 
    .FetchMany(x => x.Children) 
    .ThenFetchMany(x => x.GrandChildren) 
    .Where(x => x.Id = "someparentid") 
    .Single(); 

什麼我的發現是,有重複的子對象連接到父對象時,應該有(共3)只有一個。 (每個孩子都有3個孫子對象正確連接。)只需正確加載子集合即可。

你知道我怎樣才能實現沒有重複的孩子加載完整的父對象?

回答

2

我能夠使用通過QueryOver答案here,它正確加載,而對象生成高效的SQL(選擇每個表而不是一個巨大的聯接)。

1

你不能用NHibernate來做(因爲你的結果是笛卡兒的產品,所以我不認爲你可以用EF4來做)。你從所有表中獲得所有結果。

NHibernate不知道如何將兩個集合的結果映射回根。因此,對於每個孩子,您會得到相同數量的GrandChildren,對於每個GrandChildren,您最終會得到相同數量的孩子。

+0

@ j0k - 感謝編輯,還沒有早晨咖啡尚未:) – Phill 2011-06-01 00:11:36

+0

我我們分析了正在生成的SQL查詢,並且有兩個左連接,兩個主鍵和外鍵都具有連接條件,所以我相當肯定它不是笛卡爾的產品。過去我使用LinqToSql實現了這一點。 – Simon 2011-06-01 00:15:39

+0

@Simon - 將查詢放入SQL Server Management Studio並運行查詢,您將看到所有表的所有結果。 有可能實現相同的結果,但您必須編寫HQL。請參閱Ayende的博客深層對象圖 - http://ayende.com/blog/2580/efficently-loading-deep-object-graphs – Phill 2011-06-01 00:21:10

5

如果您將兒童和GrandChildren映射爲一組,您可以避開笛卡爾產品。您需要定義兒孫爲集合:

public class Parent 
{ 
    ... 
    public virtual ICollection<Child> Children { get; set; } 
    ... 
} 

public class Child 
{ 
    ... 
    public virtual ICollection<GrandChild> GrandChildren { get; set; } 
    ... 
} 

而且在(使用FluentNHibernate)的映射:

public class ParentMapping : ClassMap<Parent> 
{ 
    public ParentMapping() 
    { 
     ... 
     HasMany(x => x.Children) 
      .KeyColumn("ParentID") 
      .Inverse 
      .AsSet() 
     ... 
    } 
} 

public class ChildMapping : ClassMap<Child> 
{ 
    public ChildMapping() 
    { 
     ... 
     HasMany(x => x.GrandChildren) 
      .KeyColumn("ChildID") 
      .Inverse 
      .AsSet() 
     ... 
    } 
} 
+0

準確地說,查詢仍然提供笛卡爾產品,但您會得到一個Perent。 – 2011-06-01 05:21:26

+0

使用QueryOver不會遇到這種方法是否有缺點? – 2012-03-01 22:23:39

+0

感謝您的支持。我發現在類似的情況下,AsSet指令足以保證不會出現重複的情況 – mabian69 2012-08-27 15:58:56

1

如果您正在使用LINQ,你可以用這個把它簡化:

int parentId = 1; 
var p1 = session.Query<Parent>().Where(x => x.ParentId == parentId); 

p1 
.FetchMany(x => x.Children) 
.ToFuture(); 

sess.Query<Child>() 
.Where(x => x.Parent.ParentId == parentId); 
.FetchMany(x => x.GrandChildren) 
.ToFuture(); 

Parent p = p1.ToFuture().Single(); 
這裏

詳細說明:http://www.ienablemuch.com/2012/08/solving-nhibernate-thenfetchmany.html

+0

感謝邁克爾,儘管我沒有示例代碼來證明這一點,但所有這些例子都與之相關,當孩子被抓到時(他們也有孫子可以取)與父母有多對多的關係。我已經嘗試過所有這些示例(以及其他許多示例),並且在這種情況下,它們都仍然生產笛卡爾產品 – PandaWood 2016-09-13 06:29:43

+0

這很好用! – 2016-09-21 10:35:15