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" 加载来源。所以,清除你的观察者...
最后的建议 - 创建 单元测试 以仅加载根实体。最后清除会话。观察(使用探查器)是否有一些数据库命中。您可以更轻松地检查是什么原因...
我在使用 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" 加载来源。所以,清除你的观察者...
最后的建议 - 创建 单元测试 以仅加载根实体。最后清除会话。观察(使用探查器)是否有一些数据库命中。您可以更轻松地检查是什么原因...