【问题标题】:NHibernate SaveOrUpdate throws NonUniqueObjectException exceptionNHibernate SaveOrUpdate 抛出 NonUniqueObjectException 异常
【发布时间】:2021-01-21 20:46:45
【问题描述】:

我目前正在修复旧的 Windows 应用程序并遇到 NHibernate 错误。我在网上阅读并尝试了一些东西,但最终出现错误。

这是我的 ISession 代码:

Public ReadOnly Property session() As ISession
    Get
        If IsNothing(m_session) Then
            m_session = Factory.InitConfiguration.OpenSession()
        End If
        Return m_session
    End Get
End Property

这是我保存按钮的代码:

Try
    session.BeginTransaction()
    SetParent(x_object)
    'session.clear()
    session.Flush()
    session.SaveOrUpdate(x_object)
    session.Transaction.Commit()
    compObj.IsNew = False
    Return True
Catch ex As Exception
    AppServices.ErrorMessage = ex.Message
    session.Transaction.Rollback()
    Return False
Finally
    'TBA
End Try

所以问题从这里开始,我有这个日期列作为 DateTime 和 AttachmentList。

当前代码在用户键入小于 1753 的年份之前没有任何问题。但是代码正确捕获错误并显示消息,当用户继续修复年份错字时,它仍然会捕获错误(在手表上我已经获得了新值),直到用户关闭应用程序并重新打开它。

但是,如果我取消对 session.clear() 的注释,它会很好,用户可以修复他们的拼写错误并继续保存记录,但是当用户执行其他操作让我们说附件时,它会得到另一个错误.附件动作如下:

  1. 添加附件
  2. 点击保存按钮
  3. 添加新附件
  4. 点击保存按钮
  5. 新错误。

所以请告诉我需要做什么。我试过合并,我试过更新,保存,驱逐但最终出错。我认为我的问题是我如何安排会议是问题的主要根源。

【问题讨论】:

  • m_sessionx_object的范围是什么?您是否将实体映射到 DTO 之类的其他东西?
  • @A_J 是的,我将实体映射到许多子对象并将其设置为 1 个父对象。然而,弗雷德里克的解释解决了我的问题。你可以参考一下原因。

标签: vb.net nhibernate transactions


【解决方案1】:

看起来您必须处理的代码尝试继续使用经历了失败的刷新或事务提交的会话。

这是一种反模式。来自NHibernate reference

使用 NHibernate 可能会导致异常,通常是 HibernateException。 这个异常可以有一个嵌套的内部异常(根本原因),使用 InnerException 属性来访问它。

如果 ISession 抛出异常,你应该立即回滚 事务,调用 ISession.Close() 并丢弃 ISession 实例。 ISession 的某些方法不会将会话留在 一致的状态。

...

以下异常处理习语展示了 NHibernate 应用程序中的典型案例:

using (ISession sess = factory.OpenSession())
using (ITransaction tx = sess.BeginTransaction())
{
    // do some work
    ...
    tx.Commit();
}

或者,在手动管理 ADO.NET 事务时:

ISession sess = factory.openSession();
try
{
    // do some work
    ...
    sess.Flush();
    currentTransaction.Commit();
}
catch (Exception e)
{
    currentTransaction.Rollback();
    throw;
}
finally
{
    sess.Close();
}

您必须确保代码在出现异常后不会尝试继续使用会话。

此外,看起来会话在等待用户交互时保持打开状态:这不是推荐的模式。 NHibernate 会话通常是短暂的。打开会话很便宜。

通常的模式是在开始处理来自用户输入的事件时打开它,并在结束事件处理之前关闭它,以便在用户喝咖啡时不让它打开。

现在您可能很难更改应用程序会话管理,特别是如果应用程序保留对实体的引用并希望它们在等待用户交互后仍绑定到打开的会话。

如果选择在用户交互之间保持会话打开是为了“利用一级缓存”(会话实体缓存),请考虑改为激活二级缓存。

【讨论】:

  • 现在我终于从您的解释中理解并解决了我的问题,您的解释确实帮助我找到了解决方案,但是我最终使用您的代码逻辑在对象上使用 SaveOrUpdateCopy。现在是时候将这种旧方法更改为新方法了。谢谢大哥的解释!
猜你喜欢
  • 2012-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多