结果集中的NHibernate Fetch / FetchMany重复,如何修复ToFuture()

时间:2015-02-05 16:15:44

标签: nhibernate nhibernate-mapping queryover

我使用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在没有重复的单个查询中获取整个树?

1 个答案:

答案 0 :(得分:2)

我确实对这个主题有了答案,我确实使用了这个解决方案。但它最后意味着“不要使用Fetch” - 以不同的方式做。所以,请至少把它作为一个建议。

检查此Q&amp;答:

How to Eager Load Associations without duplication in NHibernate?

小引用:

  

获取收藏是一项艰难的操作。它有很多副作用(正如你所知,当有更多的集合时)。但即使提取了一个集合,我们也会加载许多重复的行。

换句话说,Fetching是一个脆弱的功能,应该在很少的情况下明智地使用,我会说。那么用什么?怎么解决?

从内置的NHibernate功能中获利:

19.1.5. Using batch fetching

  

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,因为有些可能会更高......