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

时间:2011-11-08 20:55:04

标签: 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()在大多数情况下使用。
  • 用户在域图中独占拥有一些对象,但共享父级的所有权。
  • 儿童对象上的导航属性不存在。
  • 所有类都有数字ID和数字版本字段。

用例:

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

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

根据艾恩德(http://msdn.microsoft.com/en-us/magazine/ee819139.aspx)的说法,当SOSE被抛出时:

  

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

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

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

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

我们的理论,目前:

  1. 重置C1上的版本号(以防止“未保存的值映射不正确”)
  2. 获取新会话
  3. newSession.Refresh(C1);
  4. newParent = newSession.QueryOver [...]
  5. newParent.Add(C1);
  6. newSession.SaveOrUpdate(newParent)
  7. 但是,所有文档都表明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,但相关,我认为)

1 个答案:

答案 0 :(得分:2)

  

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

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

否则,这是我当前项目用于会话可能抛出的所有可恢复异常的解决方案(例如,连接到DB丢失,外键违反,......):

  1. 在致电session.Flush()之前,会话被序列化为MemoryStream
  2. 如果session.Flush()transaction.Commit()抛出可恢复的异常,则会丢弃原始会话并对已保存的会话进行反序列化。
  3. 调用屏幕然后获取会话在异常后恢复的信息,并再次调用在第一次打开屏幕时调用的相同查询。并且因为所有修改过的实体仍处于恢复的会话中,所以用户现在处于按下save之前的状态。