我使用NHibernate相对较新,而且我遇到了一个我似乎无法自我解决的缺点。我有一个对象树,我希望在一次往返中从数据库中检索,但最终会得到一个笛卡尔积。
我尝试检索的对象称为'AccountGroup'
,'Concern'
,'Advertiser'
和'Product'
,我只希望获得活动用户所在的对象有权限。
我的初始查询如下所示:
using (var session = OpenSession())
{
return session.Query<AccountGroupEntity>()
.FetchMany(a => a.Planners)
.Where(a => a.Planners.Any(p => p.Id == userId))
.FetchMany(a => a.Concerns)
.ThenFetchMany(c => c.Advertisers)
.ThenFetch(a => a.Products)
.ToList();
}
这不会起作用,因为它将返回笛卡尔积,并且生成的实体将包含许多重复项。
但是,我不知道如何解决这个问题。我已经看到了允许我在同一个往返中执行多个查询的ToFuture()
方法,但我不知道如何以这样的方式配置我的ToFuture()
查询所有的儿童收藏都很合适。
有没有人能够了解如何使用ToFuture
在没有重复的单个查询中获取整个树?
答案 0 :(得分:2)
我确实对这个主题有了答案,我确实使用了这个解决方案。但它最后意味着“不要使用Fetch” - 以不同的方式做。所以,请至少把它作为一个建议。
检查此Q&amp;答:
小引用:
获取收藏是一项艰难的操作。它有很多副作用(正如你所知,当有更多的集合时)。但即使提取了一个集合,我们也会加载许多重复的行。
换句话说,Fetching是一个脆弱的功能,应该在很少的情况下明智地使用,我会说。那么用什么?怎么解决?
从内置的NHibernate功能中获利:
NHibernate可以有效地使用批量提取,也就是说,如果访问一个代理(或集合),NHibernate可以加载几个未初始化的代理。批量提取是懒惰选择提取策略的优化。有两种方法可以调整批处理获取:在类和集合级别上。
更容易理解批量提取类/实体。想象一下,您在运行时遇到以下情况:您在一个ISession中加载了25个Cat实例,每个Cat都有一个对其所有者的引用,一个Person。 Person类使用代理映射,lazy =“true”。如果您现在遍历所有猫并在每个猫上调用cat.Owner,NHibernate将默认执行25个SELECT语句,以检索代理所有者。您可以通过在Person:
的映射中指定批量大小来调整此行为
<class name="Person" batch-size="10">...</class>
NHibernate现在只执行三个查询,模式为10,10,5。
您还可以启用批量提取集合。例如,如果每个Person都有一个懒惰的Cats集合,并且当前在ISesssion中加载了10个人,则遍历所有人将生成10个SELECT,每个人调用一个SELECT.Cats。如果在Person的映射中为Cats集合启用批量获取,NHibernate可以预取集合:
<class name="Person">
<set name="Cats" batch-size="3">
...
</set>
我的经验,这种方法是无价的。适合我们的设置是batch-size="25"
。
如果您要求任何类型的实体(via session.Get() or .QueryOver()...)
- 直到会话开放,我们第一次触摸相关参考或集合 - 它将被分批加载... No 1 + N SELECT Issue ...
摘要:标记您的所有课程,并且batch-size="x"
(x
的所有集合可以是25)。这将支持对根实体的干净查询 - 直到会话打开,所有相关的东西都加载在少数SELECTS中。可以调整x
,因为有些可能会更高......