3

我们最近升级到最新版本的 NHibernate (3.3.3.4001),我遇到了 NHibernate 2.1.2.4000 中不存在的问题。这让我相信这可能是新的内置字节码提供程序的问题。

考虑以下映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property">
  <class name="EntityA" table="EntityA" lazy="true">

    <id name="Id" column="EntityAId">
      <generator class="native" />
    </id>

    <many-to-one name="EntityB" column="EntityBId" class="EntityB" not-null="true" />
    <many-to-one name="EntityC" column="EntityCId" class="EntityC" not-null="true" access="readonly" insert="true" update="false" />


  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property">
  <class name="EntityB" table="EntityB" lazy="true">

    <id name="Id" column="EntityBId">
      <generator class="native" />
    </id>

    <many-to-one name="EntityC" column="EntityCId" class="EntityC" not-null="true"  />

  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property">
  <class name="EntityC" table="EntityC" lazy="true">

    <id name="Id" column="EntityCId">
      <generator class="native" />
    </id>


  </class>
</hibernate-mapping>

这是我对 EntityA 的类定义:

Public Class EntityA

    Public Overridable Property Id As Integer

    Public Overridable Property EntityB As EntityB

    Public Overridable ReadOnly Property EntityC As EntityC
        Get
           Return If(EntityB IsNot Nothing, EntityB.EntityC, Nothing)
        End Get
    End Property


End Class

当我为 EntityA 的实例调用 Session.Get 时存在问题 - 它会立即导致为其相应的 EntityB 发出选择:

Session.Get(Of EntityA)(id) ' Causes the EntityB that EntityA references to be loaded as well.

我最好的猜测是字节码提供程序导致在构建代理时评估我的只读“EntityC”属性,这会强制加载引用的EntityB。

有什么方法可以避免在 NHibernate 3.3.3 中使用这种类型的模型来避免急切的负载?

4

1 回答 1

1

我在 NH 3.3.3 SP1 上对此类层次结构和映射进行了一些测试,这是我的观察结果:

  • 使用 加载 EntityA session.Get<>,然后对对象执行某些操作而不触及属性 EntityB、EntityC、EntityB 将不会被加载。触摸任一属性肯定会触发查询,这是正常的。

  • 加载 EntityA,更新与属性 EntityB 和 EntityC 无关的内容,例如更改 EntityA 名称,然后回滚事务,不发出额外的 SELECT。

  • 加载 EntityA,什么也不做,然后提交事务,为 EntityB 发出第二个 SELECT。

  • 加载 EntityA,对会话进行一些查询,然后发出 EntityB 的 SELECT。

所有测试都在 FlushMode.Auto 下完成。

从这些,我得出结论,NHibernate 在这种情况下的行为是完全可以预料的:在进行刷新时,NH 需要检查对象是否脏污,它需要获取属性 EntityC 的值与之前的值进行比较,而这是什么触发了有问题的 SELECT。

这绝对不是因为session.Get<>或新的代理。您可以轻松地进行更多测试来证明这一点。不过,我不明白为什么 NH 2.1.2 会有所不同。

我还尝试了在 NH 3.3.1 上的测试,响应与 NH 3.3.3 SP1 完全相同。

于 2013-09-17T04:32:10.523 回答