我們試圖在拋出StaleObjectStateException之後合併對象以保存合併副本。如何在NHibernate StaleObjectStateException之後優雅地合併對象圖?
下面是我們的環境狀況:
- 列表項
- 多用戶系統
- WPF Desktop應用程序,SQL Server 2008數據庫
- NHibernate的3.1.0.4000,FluentNHibernate 1.2.0.712
- 全球性的,長期運行的NHibernate會話[暫時。我們瞭解會議每位演示者是推薦模式,但目前我們的項目時間表沒有時間進行轉換。]
- 自上而下保存和屬性導航(也就是說我們保存頂級對象(在我們的域圖中)
- .Cascade.AllDeleteOrphan()在大多數情況下使用。
- 用戶只擁有域圖中的一些對象,但共享父對象的所有權。
- Children對象的導航屬性不存在。
- 所有類都有數字ID和數字版本字段。
使用案例:
- 用戶1個啓動應用程序並打開父。
- 用戶2啓動應用程序並打開Parent。
- 用戶2添加一個孩子(此處爲C2)。
- 用戶2保存父。
- 用戶1添加一個孩子(此處爲C1)。
- 用戶1保存父。
- 用戶1接收StaleObjectStateException(這是正確的)
我們要優雅地處理例外。 因爲用戶共享父項的所有權,所以用戶1應該能夠成功保存,並將父項與他的新孩子以及用戶2的孩子一起保存。
當SOSE被拋出,根據Ayende(http://msdn.microsoft.com/en-us/magazine/ee819139.aspx):
您的會話和其加載實體敬酒,因爲與NHibernate,從會話拋出 一個異常會話移動到一個未定義的狀態。你可以不再使用該會話 或任何裝載的實體
C1已經被現在而不是無用的會話分配一個ID和版本號。 (我希望它沒有。)
我們如何結合使用ISession.Merge()和ISession.Refresh()來獲得一個新保存的同時擁有C1和C2的父?
我們嘗試了一些神祕的組合,其中沒有一個完全奏效。 通常情況下,無論是「行被其它事務更新或刪除(或者未保存值的映射是不正確的」,或在ODBC水平的實際ID碰撞
我們的理論,此刻:
- 重置C1版本號(以防止 「未保存值的映射是不正確」)
- 獲取一個新的會話
- newSession.Refresh(C1);
- newParent = newSession.QueryOver [...]
- newParent.Add(C1);
- newSession.SaveOrUpdate(newParent)
然而,所有的文檔建議newSession.Merge是應該是足夠的。
用作研究其他職位:
Fluent NHibernate Newbie: Row was updated or deleted by another transaction
Is there an alternative to ISession.Merge() that doesn't throw when using optimistic locking?
StaleObjectstateException row was updated or deleted by
How I can tell NHibernate to save only changed properties
Hibernate (JPA): how to handle StaleObjectStateException when several object has been modified and commited(java的,但相關的,我認爲)
看起來我們需要同時修復我們的映射文件,然後使用session.Replicate(obj,ReplicationMode.overwrite) - 除非所有內容都是可序列化的,並且仍然是我們的版本號導致StaleObject再請 – BufferUnderrunOK
注意:這仍然不是我最喜歡的答案,但是cremor已經贏得了賞金。 :) – BufferUnderrunOK