2

私はいくつかのオブジェクトがドキュメントのリスト、他のオブジェクト、...何でも持っているオブジェクトを持っています。lazy=falseアプリケーションが非常に遅くなるため、この関係では使用したくありません。Lockを使用してオブジェクトを再アタッチできるため、他のプロパティまたは1対多の関係が必要なときに読み込まれます。しかし、コレクションの場合、コレクションにアクセスしようとすると、常に「コレクションを初期化できませんでした」というメッセージが表示されます。Lock(obj)その場所に接続されているオブジェクトを呼び出すと機能しません。

マッピングを次のようにしたいと思います。

<set name="DocumentList" table="material_document" cascade="all" lazy="true">
  <key column="material_id"/>
  <many-to-many class="Document">
    <column name="document_id"/>
  </many-to-many>
</set>

再接続する方法はありますか?または、マッピング設定はありますか?

update1:

これは、材料側のマッピングです。

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
<class name="Material" table="material">
<!-- Defining PK -->
<id name="Id" type="integer" column="id">
    <generator class="sequence">
      <param name="sequence">material_id_seq</param>
    </generator>
</id>
<!-- Defining Properties -->
<!-- Defining FK-Relations -->
<set name="DocumentList" table="material_document" cascade="all" lazy="false">
  <key column="material_id"/>
  <many-to-many class="Document">
    <column name="document_id"/>
  </many-to-many>
</set>

ドキュメントマッピングファイルには、関係に関する情報はありません。データベース名は大丈夫です、他のすべては機能します。テーブルは、、およびと呼ばmaterialmaterial_documentますdocument。私のクラスはpublicとプロパティpublic virtualです。私のエンティティの何が問題になっている可能性がありますか?データの何かが間違っているということですか、それともプログラム内のオブジェクトに何かが起こった可能性があるということですか...?

List material = LoadAllMaterials();
//some code, that causes the session to be closed, a new session will be opened
foreach (Document d in material.DocumentList) { //causes the exception
    //do something
}

その前に、事前にロードせずにドキュメントをフェッチしたいと思います。

更新2: 現在オブジェクトを再アタッチする方法:プロキシがあり、それが別の方法で機能しないことがわかっている場合は、forceをtrueに設定します...そして、それを呼び出すとevictが例外をスローするため、セッション内にあるかどうかを確認する必要がありますセッションにないオブジェクト。

public void Reattach(Type type, BaseObject o, bool force)
{
    bool inSession = o.IsInSession();

    if (force && inSession)
    {
        GetSession().Evict(o);
        GetSession().Lock(type.ToString(), o, LockMode.None);
    }
    else {

        o = (BaseObject)GetSession().GetSessionImplementation().PersistenceContext.Unproxy(o);

        if (!inSession) {

            GetSession().Lock(type.ToString(), o, LockMode.None);
        }
    }
}

これは私のIsInSession()メソッドです:

public virtual bool IsInSession() {

    ISession session = HibernateSessionManager.Instance.GetSession();

    var pers = session.GetSessionImplementation()
          .GetEntityPersister(GetType().ToString(), this);

    NHibernate.Engine.EntityKey key = new NHibernate.Engine.EntityKey(Id,
        pers, EntityMode.Poco);

    bool isInSession = false;

    try
    {
        object entity = session.GetSessionImplementation().PersistenceContext.GetEntity(key);

        if (entity != null)
        {
            isInSession = true;
        }
    }
    catch (NonUniqueObjectException) {}

    return isInSession;
}
4

1 に答える 1

2

マッピングの1つにlazy="false"が含まれていることはわかります...NHibernateはデフォルトで遅延読み込みを使用するため、マッピングからすべてのlazy="false"およびlazy="true"ステートメントを削除してそのまま実行しますNHibernateのデフォルトを使用します。

次のNUnitテストを作成しましたが、両方のテストに合格したため、問題を再現できませんでした。つまり、lazy = "false"マッピングの問題か、その他の問題のいずれかです...完全なものがないと、これらの問題を診断することは常に困難です。あなたの目の前のアプリケーション...

次のテストケースを使用して、次のエラーを作成できました:「Initializing [SampleApplication.Customer#19]-ロールのコレクションを遅延初期化できませんでした:SampleApplication.Customer.Addresses、セッションまたはセッションが閉じられていません」

[Test]
public void Testing_A_Detached_Entity()
{
    // Arrange
    var sessionFactory = ObjectFactory.GetInstance<ISessionFactory>();

    Customer customer = null;

    using ( ISession session = sessionFactory.OpenSession() )
    {
        using ( ITransaction tx = session.BeginTransaction() )
        {
            customer = session.Query<Customer>()
                .Where( x => x.CustomerNbr == 19 )
                .FirstOrDefault();
        }
    }

    // Act
    TestDelegate actionToPerform = () =>
       {
           // Looping over this child collection should throw an Exception
           // because we no longer have an active NHibernate session
           foreach ( var address in customer.Addresses )
           {

           }
       };

    // Assert
    Assert.Throws<NHibernate.LazyInitializationException>( actionToPerform );
}

次のテストケースとNHibernateのsession.Lock()メソッドを使用して、デタッチされたオブジェクトを正常に再アタッチし、子コレクションのカウントを取得することができました。

[Test]
public void Testing_Reattaching_A_Detached_Entity()
{
    // Arrange
    var sessionFactory = ObjectFactory.GetInstance<ISessionFactory>();

    Customer customer = null;

    using ( ISession session = sessionFactory.OpenSession() )
    {
        using ( ITransaction tx = session.BeginTransaction() )
        {
            customer = session.Query<Customer>()
                .Where( x => x.CustomerNbr == 19 )
                .FirstOrDefault();
        }
    }

    // Act
    ISession newSession = sessionFactory.OpenSession();

    newSession.Lock( customer, LockMode.None );

    // Assert
    Assert.That( customer.Addresses.Count > 0 );
}
于 2012-08-30T20:22:41.503 に答える