在 NHibernate 中强制进行急切的选择

Posted

技术标签:

【中文标题】在 NHibernate 中强制进行急切的选择【英文标题】:Force an eager select in NHibernate 【发布时间】:2010-12-26 16:23:27 【问题描述】:

我正在尝试使用选择来急切地获取集合,但我只是 获取是 inner 连接。怎么回事?

Session.CreateCriteria(typeof(Foo))
    .SetFetchMode("Bars", FetchMode.Select)
    .CreateAlias("Bars", "b")
    .SetFetchMode("b.Bazes", FetchMode.Select)
    .List();

我尝试将 FetchMode 更改为 Eager,但这不起作用 - 我 仍然获得内部连接而不是单独的选择。我不确定它从哪里获得内部连接,因为文档中没有任何内容谈到 FetchMode 导致内部连接。 是否有可能获得急切的选择?

更新 好的,我发现创建别名会导致内部连接。所以我可以使用 .CreateAlias("Bars", "b", JoinType.None),但是 b.Bazes 的获取会恢复为延迟加载。呃。

【问题讨论】:

【参考方案1】:

INNER JOIN 是 NHibernate 加载您的记录及其相关子记录的方式。这通常是最有效的方法。

如果要使用多个 SELECT 语句,则子项查询需要以某种方式包含父项的条件。 INNER JOIN 可以很容易地获得相关的孩子,NHibernate 会在运行查询后正确地将其拆分为多个实体。

我相信 Entity Framework 4 将允许您执行多个查询并“神奇地”重新附加相关对象,但我不知道 NHibernate 有这样的功能(如果我错了,我相信有人会纠正我关于这个)。

【讨论】:

但是默认的连接类型通常是左外连接不是吗?如果外键可以为空,或者在我的情况下,Bars 可能为空,则内部连接不起作用。此外,文档似乎表明您可以进行急切的选择。【参考方案2】:
Session.CreateCriteria(typeof(Foo))
   .SetFetchMode("Bars", FetchMode.Select)
   .CreateAlias("Bars", "b")  <-- this line triggers a join ( think )
   .SetFetchMode("b.Bazes", FetchMode.Select) 
   .List();

如果你真的不想加入,你可以在映射中指定 fetch="select",但这会导致不推荐的 N+1 选择(每个 Foo 实体选择一个,然后每个 Baze 一个选择)

【讨论】:

【参考方案3】:

为了让 nhibernate 急切加载实体,使用左外连接。所以你需要像这样改变你的代码:

Session.CreateCriteria(typeof(Foo))
.SetFetchMode("Bars", FetchMode.Select)
.CreateAlias("Bars", "b", JoinType.LeftOuterJoin)
.SetFetchMode("b.Bazes", FetchMode.Select)
.List();

它在similar scenario 中帮助了我。

【讨论】:

以上是关于在 NHibernate 中强制进行急切的选择的主要内容,如果未能解决你的问题,请参考以下文章

Fluent NHibernate:在映射中急切加载多个集合

如何让 Nhibernate 重建数据库?

在 NHibernate 3.0 Linq 中急切加载多个兄弟姐妹和孙辈(堂兄弟?)的良好行为

Nhibernate:只读属性导致急切加载

NHibernate 急切负载

Nhibernate - 分页和急切加载实体