NHibernate SaveOrUpdate错误

时间:2017-03-03 09:28:49

标签: vb.net nhibernate transactions

我目前正在修复旧的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之前没有任何问题。但是代码正确捕获错误并显示消息,当用户继续修复年份错误时,它&# 39; ll仍然捕获错误(在监视时我已经获得新值),直到用户关闭应用程序并重新打开它。

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

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

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

2 个答案:

答案 0 :(得分:0)

您尚未提及m_sessionx_object对象的范围。此外,您还没有提到如何处理实体。您是否将实体映射到DTO之类的其他内容?

让我们看看为什么会发生这种情况:

这可能由于第一级(会话)缓存而发生。你试图SaveOrUpdate一个实体;它由于数据不正确而失败。但是,实体仍处于会话缓存中。然后用户纠正错误并再次保存。您使用实体再次SaveOrUpdate与实体已在会话中冲突。两个实体的标识符相同。

参考thisthis问题。

当您取消注释session.clear()时,第一个实体会离开会话并且您的新实体正常工作,因为现在没有冲突。

我上面提到的链接还建议如何处理此方案而不是clear()

在我的理解中,

Clear不是一个好的解决方案;它将清除整个会话。 Evict是更好的选择。如果Evict对您不起作用,可能是您没有驱逐正确的实例。

以下是C#代码;你需要将它翻译成VB.NET: -

try
{
    nhSession.SaveOrUpdate(instance);
}
catch(NonUniqueObjectException)
{
    T instanceFromCache = GetInstanceFromCache<T>(instance);
    nhSession.Evict(instanceFromCache);
    nhSession.SaveOrUpdate(instance);
}

您可以从我上面提到的其中一个链接获取GetInstanceFromCache方法。

答案 1 :(得分:0)

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

这是一种反模式。来自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会话通常是短暂的。开会很便宜。

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

现在您可能很难更改应用程序会话管理,尤其是当应用程序保留对实体的引用并期望它们在等待用户交互后仍然绑定到已打开的会话。

如果在&#34;利用第一级缓存&#34; (会话实体缓存),请考虑激活二级缓存。