NHibernate 总是水合多对一

NHibernate always hydrates many-to-one

我在使用 NHibernate 时遇到了一些奇怪的事情。我已经打开了一个不是我写的代码库,而我写的代码库已经不在了。所以我想我正在寻找的是关于调试的更多提示。

我正在使用 NHIbernate 3.4 Linq 提供程序来查询与另一个实体具有多对一关系的实体。

我看到的是,尽管我从未访问过代表多对一关系的 属性,但它始终处于水合状态。通过 NHibernate 探查器查看查询,我可以看到 属性 似乎是延迟加载的。使用我的调试器设置断点我可以看到 属性 从未被访问过。

使用 NHibernate 探查器时,我可以看到它发生在我加载父实体列表时,但不是在同一个查询中。

我不知道为什么会这样,但它会导致 N+1 问题。

实体在 hbm.xml 个文件中定义。

所以我要的是输入我应该开始挖掘的地方。我觉得我已经把我能想到的都试过了。

我几乎可以肯定地说,问题不在 NHibernate 上,而是在使用方面(我们都同意我会说)

所以,我们应该以(隐式或显式)为起点的是惰性设置:

// class level
// by default lazy is turned on
<class name="Entity" ... lazy="true" ... >
   ...

// reference many-to-one level, also by default lazy
<many-to-one name="Entity" lazy="proxy" ... />

为了避免 N+1,我们应该确保我们使用带有 batch-size 设置的批量提取,see more here

// class/entity level
// ATTENTION - this is not implicit, we have to define that
<class name="Entity" ... lazy="true" ... batch-size="25" >
  ...

// collection level
// ATTENTION - this is not implicit, we have to define that
<bag name="Entities" ... batch-size="25">
...

有了它,现在 NHibernate 本身将永远不会加载超过需要的内容。那么当需要加载参考时,典型的用例是什么?

覆盖时:

public override bool Equals(object obj)
{
}
public override int GetHashCode()
{
}

这些方法应该(有时 - 对于 composite-id,甚至必须)覆盖,以提供业务唯一键。检查是否有任何参考值未用于此类比较(例如,国家和办事处的组合对于某些其他实体而言是唯一的)

最后 但并非最不重要,您的调试器可能有问题。调试器实际上正在影响加载,因为每当我们在调试中观察到任何东西时 window ...我们强制 NHibernate 加载惰性的东西。

令人惊讶的是,这是最常见的 "forced" 加载来源。所以,清除你的观察者...

最后的建议 - 创建 单元测试 以仅加载根实体。最后清除会话。观察(使用探查器)是否有一些数据库命中。您可以更轻松地检查是什么原因...