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 に触れずにオブジェクトを操作します。エンティティ B はロードされません。いずれかのプロパティに触れると、確実にクエリがトリガーされますが、これは正常です。

  • EntityA をロードし、EntityA の名前を変更するなど、プロパティ EntityB および EntityC に関連しない何かを更新してから、トランザクションをロールバックします。追加の SELECT は発行されません。

  • EntityA をロードし、何もせずにトランザクションをコミットすると、EntityB の 2 番目の 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 に答える