マージされたコピーを保存するために StaleObjectStateException がスローされた後、オブジェクトを結合しようとしています。
当社の環境状況は次のとおりです。
- リスト項目
- マルチユーザーシステム
- WPF デスクトップ アプリケーション、SQL Server 2008 データベース
- NHibernate 3.1.0.4000、FluentNHibernate 1.2.0.712
- グローバルで長期にわたる NHibernate セッション [今のところ. プレゼンターごとのセッションが推奨されるパターンであることは理解していますが、現時点ではプロジェクト スケジュールに変換する時間がありません。]
- トップダウン保存とプロパティ ナビゲーション (つまり、トップレベル オブジェクト (ここでは親と呼ばれます) をドメイン グラフに保存します)
- ほとんどの場合、.Cascade.AllDeleteOrphan() が使用されます。
- ユーザーは、ドメイン グラフ内のいくつかのオブジェクトを排他的に所有しますが、親の所有権を共有します。
- Children オブジェクトのナビゲーション プロパティは存在しません。
- すべてのクラスには、数値の ID フィールドと数値のバージョン フィールドがあります。
使用事例:
- ユーザー 1 がアプリケーションを起動し、親を開きます。
- ユーザー 2 がアプリケーションを起動し、親を開きます。
- ユーザー 2 が子 (ここでは C2) を追加します。
- ユーザー 2 が親を保存します。
- ユーザー 1 が子 (ここでは C1) を追加します。
- ユーザー 1 が親を保存します。
- ユーザー 1 は StaleObjectStateException を受け取ります (当然のことです)
例外を適切に処理したいと考えています。ユーザーは親の所有権を共有しているため、ユーザー 1 は正常に保存でき、新しい子とユーザー 2 の子の両方で親を保存できます。
Ayende ( http://msdn.microsoft.com/en-us/magazine/ee819139.aspx )によると、SOSE がスローされると、次のようになります。
NHibernate では、セッションから例外がスローされると、そのセッションが未定義の状態に移行するため、セッションとその読み込まれたエンティティは乾杯します。そのセッションまたは読み込まれたエンティティは使用できなくなります
C1 には、現在では役に立たないセッションによって ID とバージョン番号が既に割り当てられています。(そうでなかったらよかったのに。)
ISession.Merge() と ISession.Refresh() の使用を組み合わせて、 C1 と C2 の両方を持つ新しく保存された Parent を取得するにはどうすればよいでしょうか?
私たちは多くの難解な順列を試しましたが、どれも完全には機能しませんでした。通常、「行が別のトランザクションによって更新または削除された (または保存されていない値のマッピングが正しくなかった)」か、ODBC レベルでの実際の ID の衝突のいずれかです。
現時点での私たちの理論:
- C1 のバージョン番号をリセットします (「保存されていない値のマッピングが正しくない」ことを防ぐため)
- 新しいセッションを取得する
- newSession.Refresh(C1);
- newParent = newSession.QueryOver[...]
- newParent.Add(C1);
- newSession.SaveOrUpdate(newParent)
ただし、すべてのドキュメントは、newSession.Merge で十分であることを示唆しています。
研究として使用されるその他の投稿:
流暢な NHibernate 初心者: 別のトランザクションによって行が更新または削除され
た
StaleObjectstateException 行は、
変更されたプロパティのみを保存するように NHibernate に指示する方法
によって更新または削除されました
。