1

オブジェクトを再度初期化する必要がある場合は、オブジェクトでこの関数を呼び出します。

public virtual void Initialize()
{
    if (!HibernateSessionManager.Instance.GetSession().Contains(this)) {

        try
        {
            HibernateSessionManager.Instance.GetSession()
                             .Lock(this, NHibernate.LockMode.None);
        }
        catch (NonUniqueObjectException e) { }
    }
}

をチェックすることで何かを2回初期化するのを防ぐことができると思ってContains(this)いましたがLock(this, NHibernate.LockMode.None)NonUniqueObjectException. これまでのところ、機能するため無視していますが、オブジェクトをロックする理由とより良い方法を知りたいです。

敬具、期待

4

2 に答える 2

3

これはおそらく、アイデンティティ マップのどこかに違反していることを意味します。これは、同じデータベース ID を持つオブジェクトの 2 つのインスタンスがぶらぶらしていることを意味しますが、参照 ID は異なります。

Session.Contains は参照の等価性をチェックしますが、セッション内に同じ型と ID を持つものが既に存在する場合、Lock は例外をスローします。これは厳密な比較ではありません。

Equals と GetHashCode の単純な実装 (非常に単純で推奨されない) を使用して、AdventureWorks データベースで次のテストを検討してください。

 using (ISession session = SessionFactory.Factory.OpenSession())
        {
            int someId = 329;

            Person p = session.Get<Person>(someId);
            Person test = new Person() { BusinessEntityID = someId };

            Assert.IsTrue(p.Equals(test)); //your code might think the objects are equal, so you'd probably expect the next line to return true         

            Assert.IsFalse(session.Contains(test)); //But they're not the same object

            Assert.Throws<NonUniqueObjectException>(() =>
            {
                session.Lock(test, LockMode.None); //So when you ask nhibernate to track changes on both objects, it gets very confused
            });
        }

NHibernate (および ORM だと思います) は、オブジェクトへの変更を追跡することで機能します。そのため、Get'ing Person 329 では、Hibernate に Person の特定のインスタンスに何が起こっても注意を払うように依頼します。彼の名をハイメに変更するとしましょう。

次に、同じ Id を持つ person の別のインスタンスを取得します (この場合、新しく作成しただけですが、そのようなオブジェクトを取得するための多くの陰湿な方法があります)。NHibernate でこれをセッションにもアタッチできると想像してみてください。この 2 番目のオブジェクトの名を Robb のような名前に設定することもできます。

セッションをフラッシュするとき、NHibernate には、データベースの行を Robb または Jaime のいずれかに同期する必要があるかどうかを知る方法がありません。したがって、それが発生する前に、一意でない方法をスローします。

理想的には、これらの状況が発生しないようにする必要がありますが、何が起こっているのかがよくわかっている場合は、session.Merge を確認してください。これにより、追跡された状態を、最後にマージされたものに強制できます (例では Robb)。 .

于 2012-08-13T20:15:51.557 に答える
0

問題は完全に異なっていました-オーバーライドしない場合の参照による同等性のチェックが含まれていますEquals()。今では私の質問のコードで動作します!

    public override bool Equals(object obj)
    {
        if (this == obj) { 

            return true;
        } 

        if (GetType() != obj.GetType()) {

            return false;
        }

        if (Id != ((BaseObject)obj).Id)
        {

            return false;
        }

        return true;
    }
于 2012-08-21T06:49:30.477 に答える