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

NHibernate Fetch/FetchMany duplication in resultset, how to fix with ToFuture()

我对使用 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();
}

这不会起作用,因为它会 return 笛卡尔积并且生成的实体将包含许多重复项。

但是,我不知道如何解决这个问题。我已经看到 ToFuture() 方法允许我在同一往返中执行多个查询,但我不知道如何配置我的 ToFuture() 查询以填充所有子集合正确。

谁能告诉我如何使用 ToFuture 在单个查询中获取整棵树而不重复?

我确实有这个主题的答案,我确实使用了解决方案。但它最后意味着 "do not use Fetch" - 做不同的事情。所以,请至少把它作为一个建议。

查看此问答:

How to Eager Load Associations without duplication in NHibernate?

小引用:

Fetching Collections is a difficult operation. It has many side effects (as you realized, when there are fetched more collections). But even with fetching one collection, we are loading many duplicated rows.

换句话说,Fetching 是一个脆弱的特性,应该在极少数情况下明智地使用,我会说。那要用什么?如何解决?

受益于内置的 NHibernate 功能:

19.1.5. Using batch fetching

NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.

Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in an ISession, each Cat has a reference to its Owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call cat.Owner on each, NHibernate will by default execute 25 SELECT statements, to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:

<class name="Person" batch-size="10">...</class>

NHibernate will now execute only three queries, the pattern is 10, 10, 5.

You may also enable batch fetching of collections. For example, if each Person has a lazy collection of Cats, and 10 persons are currently loaded in the ISesssion, iterating through all persons will generate 10 SELECTs, one for every call to person.Cats. If you enable batch fetching for the Cats collection in the mapping of Person, NHibernate can pre-fetch collections:

<class name="Person">
    <set name="Cats" batch-size="3">
        ...
    </set>

我的经验,这种方法是无价的。对我们有用的设置是 batch-size="25".

如果您要求任何类型的实体 (via session.Get() or .QueryOver()...) - 在 session 打开之前,我们第一次接触相关参考或 collection - 它会分几批加载.. . No 1 + N SELECT 问题...

总结:用batch-size="x"标记所有类,所有collectionx可能是25)。这将支持对根实体的干净查询 - 在 session 打开之前,所有相关内容都将在 SELECTS 内加载。 x 可以调整,有些可以更高...