C# 如何使用NHibernate加载大型复杂对象图

C# 如何使用NHibernate加载大型复杂对象图,c#,nhibernate,C#,Nhibernate,给定一个对象图,如: A { IEnum<B> } B { IEnum<C>, IEnum<D>, IEnum<E>, ... } C { IEnum<X> } A{IEnum} B{IEnum,IEnum,IEnum,…} C{IEnum} 如何在没有N+1问题的情况下急切地加载整个对象图 下面是我最终想要执行的查询的伪代码: var a = Session.Get<A>(1); // Query 1 var b_Id

给定一个对象图,如:

A { IEnum<B> }
B { IEnum<C>, IEnum<D>, IEnum<E>, ... }
C { IEnum<X> }
A{IEnum}
B{IEnum,IEnum,IEnum,…}
C{IEnum}
如何在没有N+1问题的情况下急切地加载整个对象图

下面是我最终想要执行的查询的伪代码:

var a = Session.Get<A>(1); // Query 1
var b_Ids = foreach(b in A.B's) => Select(b.Id); // Query 2
var c = Session.CreateQuery("from C where B in (b_Ids)").Future<C>(); // Query 3
var d = Session.CreateQuery("from D where B in (b_Ids)").Future<D>(); // Query 3
var e = Session.CreateQuery("from E where B in (b_Ids)").Future<E>(); // Query 3

// Iterate through c, d, e, ... find the correct 'B' parent, add to collection manually
var a=Session.Get

更新2: 乔丹的回答让我找到了以下与我的问题相关的帖子:和。此时的悬而未决的问题是“如何在没有每条路径往返的情况下执行子选择”

更新3:
我已经接受了Jordan的答案,尽管subselect解决方案不是最优的。

首先,您可以更改映射以加载这些集合。参见中的第4项。
其次,我认为您的集合似乎要加载两次的原因是您首先使用查询获取它,然后使用集合属性。
含义-nHibernate区分用户生成的查询(如您使用的查询)和用户自己生成的查询(如您第一次读取“C”集合时发生的查询)。它们不会混合。
因此,当您第一次读取“C”集合时,nHib无法识别它实际上曾经向DB发送过完全相同的查询(因为它是一个用户查询),并再次发送它。

避免这种情况的方法是通过B实体检索C集合。

您可以使用可在映射文件中设置的子选择获取。这将避免N+1和笛卡尔积。

我想你错过了我说的“没有N+1问题”这一部分,这才是真正的问题。当您急于加载这样的对象模型时,您会遇到N+1查询。在我的示例中,对于每个“B”,您将有一个唯一的“C”、“D”和“E”查询(10B=10C+10D+10E=30个查询!)。@Pat:您可以使用“fetch type=join”选项在与问题中提到的AsAlso相同的查询中加载您的Bs/Cs/Ds:“到目前为止,我遇到的唯一一件事就是加入B-C、B-D、B-E,这在我的情况下是不可接受的。“默认情况下,NH将在所有儿童中创建笛卡尔乘积,这很糟糕。criteria api可以独立地对每个子表进行联接,但由于这些子表是100mil+记录,我们的DBA将不接受联接。而且,B、C和D都是简单的问题;我们实际上有11个子集合在这个级别上。我认为这将适用于深度为1的集合,并导致深度为2的集合为N+1,但情况似乎并非如此。从一个测试应用程序来看,你似乎只得到了两个级别的子选择。我无法想象次级选区会如此昂贵,他们应该利用地方性原则。。。有趣。往返次数仍然是一个问题-您能想出一种方法将所有子选择批处理到一个往返中吗?我使用的是SQLite,因此不支持批处理。我想您可以使用NHibernate在这个场景中使用的ADO.NET批处理。我得出的结论是,在当前NH中这是不可能的(不修改源代码)。。。这个问题和我现在的问题是一样的:-我会投票支持你的答案,但我没有注册:(没问题。如果你记得你注册的时候,我很感激。祝你好运!
void Add(IEnum<C>)
{
    _collection = new Collection<C>(); // replace the proxied instance to prevent initialization
    foreach(c) => _collection.Add(c);
}