在NHibernate StaleObjectStateException之后如何优雅地合并对象图?

Buf*_*nOK 9 nhibernate fluent-nhibernate optimistic-locking staleobjectstate

我们正在尝试在抛出StaleObjectStateException之后组合对象以保存合并副本.

这是我们的环境状况:

  • 项目清单
  • 多用户系统
  • WPF桌面应用程序,SQL Server 2008数据库
  • NHibernate 3.1.0.4000,FluentNHibernate 1.2.0.712
  • 全球,长期运行的NHibernate会议[目前.我们了解会话演示者是推荐的模式,但目前没有时间在我们的项目进度表中进行转换.
  • 自上而下的保存和属性导航(也就是说我们在域图中保存顶级对象(此处称为Parent))
  • .Cascade.AllDeleteOrphan()在大多数情况下使用.
  • 用户独占拥有域图中的某些对象,但共享Parent的所有权.
  • Children对象上的导航属性不存在.
  • 所有类都有数字ID和数字版本字段.

使用案例:

  • 用户1启动应用程序并打开Parent.
  • 用户2启动应用程序并打开Parent.
  • 用户2添加一个孩子(此处为C2).
  • 用户2保存父母.
  • 用户1添加一个孩子(此处为C1).
  • 用户1保存父母.
  • 用户1收到StaleObjectStateException(这是正确的)

我们希望优雅地处理异常.由于用户共享父级的所有权,因此用户1应该能够成功保存,并使用他的新孩子和用户2的孩子保存父级.

根据Ayende(http://msdn.microsoft.com/en-us/magazine/ee819139.aspx),当SOSE被抛出时:

您的会话及其加载的实体是toast,因为使用NHibernate时,会话抛出的异常会将该会话移动到未定义状态.您无法再使用该会话或任何已加载的实体

已经为现在没有用的会话分配了一个ID和版本号.(我希望它没有.)

我们如何结合使用ISession.Merge()和ISession.Refresh()来获得一个同时具有C1和C2的新保存的Parent?

我们已经尝试了许多奥术排列,其中没有一个完全奏效.通常,"行已被另一个事务更新或删除(或未保存的值映射不正确")或ODBC级别的实际ID冲突.

我们的理论,目前:

  1. 重置C1上的版本号(以防止"未保存的值映射不正确")
  2. 获得一个新的会话
  3. newSession.Refresh(C1);
  4. newParent = newSession.QueryOver [...]
  5. newParent.Add(C1);
  6. newSession.SaveOrUpdate(newParent)

但是,所有文档都表明newSession.Merge 应该足够了.

用作研究的其他帖子:
Fluent NHibernate Newbie:Row被另一个事务更新或删除
是否有使用乐观锁定时不会抛出的ISession.Merge()的替代方法?
StaleObjectstateException行已更新或删除
如何告诉NHibernate只保存已更改的属性
Hibernate(JPA):如何在修改和提交多个对象时处理StaleObjectStateException(java,但相关,我认为)

cre*_*mor 2

由于用户共享父级的所有权,因此用户 1 应该能够成功保存,并保存父级及其新子级和用户 2 的子级。

为什么不在子集合上禁用乐观锁定呢?然后任何人都可以添加子级,并且不会增加父级的版本。

否则,这是我当前项目用于会话可能引发的所有可恢复异常的解决方案(例如,与数据库的连接丢失、外键违反等):

  1. 在调用之前,session.Flush()会话被序列化为MemoryStream.
  2. 如果session.Flush()transaction.Commit()引发可恢复的异常,则原始会话将被释放,并反序列化保存的会话。
  3. 然后,调用屏幕获取会话在异常后恢复的信息,并再次调用与第一次打开屏幕时调用的相同查询。由于所有修改的实体仍处于恢复的会话中,因此用户现在处于按下“保存”之前的状态。