我们正在尝试在抛出StaleObjectStateException后合并对象以保存合并后的副本。
以下是我们的环境情况:
- 多用户系统 - WPF桌面应用程序,SQL Server 2008数据库 - NHibernate 3.1.0.4000,FluentNHibernate 1.2.0.712 - 全局长时间运行的NHibernate会话[目前为止。我们了解每个Presenter一个Session是推荐的模式,但目前项目进度没有时间进行转换。] - 自上而下的保存和属性导航(即我们在领域图中保存顶层对象(以下称为Parent)) - 在大多数情况下使用.Cascade.AllDeleteOrphan()。 - 用户独占领域图中的某些对象,但共享Parent的所有权。 - Children对象上不存在导航属性。 - 所有类都有数字ID和数字版本字段。
用例:
我们尝试了许多复杂的排列组合,但没有一个完全起作用。通常会出现“行已被另一个事务更新或删除(或unsaved-value映射不正确)”或ODBC级别上实际ID冲突的情况。
我们目前的理论是:
以下是我们的环境情况:
- 多用户系统 - WPF桌面应用程序,SQL Server 2008数据库 - NHibernate 3.1.0.4000,FluentNHibernate 1.2.0.712 - 全局长时间运行的NHibernate会话[目前为止。我们了解每个Presenter一个Session是推荐的模式,但目前项目进度没有时间进行转换。] - 自上而下的保存和属性导航(即我们在领域图中保存顶层对象(以下称为Parent)) - 在大多数情况下使用.Cascade.AllDeleteOrphan()。 - 用户独占领域图中的某些对象,但共享Parent的所有权。 - Children对象上不存在导航属性。 - 所有类都有数字ID和数字版本字段。
用例:
- 用户1启动应用程序并打开父级。
- 用户2启动应用程序并打开父级。
- 用户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的新保存的父级?我们尝试了许多复杂的排列组合,但没有一个完全起作用。通常会出现“行已被另一个事务更新或删除(或unsaved-value映射不正确)”或ODBC级别上实际ID冲突的情况。
我们目前的理论是:
- 重置C1的版本号(以防止“unsaved-value映射不正确”)
- 获取一个新会话
- newSession.Refresh(C1);
- newParent = newSession.QueryOver[...]
- newParent.Add(C1);
- newSession.SaveOrUpdate(newParent)
其他用作研究的帖子:
Fluent NHibernate 新手:行已被另一个事务更新或删除
有没有一种替代 ISession.Merge() 的方法,在使用乐观锁定时不会抛出异常?
StaleObjectstateException 行已被更新或删除
如何告诉 NHibernate 仅保存已更改的属性
Hibernate(JPA):当多个对象已被修改和提交时如何处理 StaleObjectStateException(Java,但相关,我认为)