【问题标题】:Nhibernate: Handling an ITransaction Exception So That New Transactions Can Continue with same ISessionNhibernate:处理 ITransaction 异常,以便新事务可以继续使用相同的 ISession
【发布时间】:2009-01-29 22:04:45
【问题描述】:

我有一个包含 10 个数据对象的列表,我想使用 NHibernate 将它们插入/更新到数据库中。如果一个抛出异常(比如主键违规),我仍然想插入/更新另一个 9. 我将每个对象操作滚动到它自己的原子事务中,如果有异常则回滚事务。问题是,如果事务确实导致异常并回滚,则在下一个事务中 Nhibernate 抱怨错误:Nexus.Data.PortfolioCorporateEntity 条目中的 null id (发生异常后不刷新会话)

我的主程序很简单。它从会话工厂创建会话,创建数据访问层,对数据对象进行一些处理,然后尝试将这些数据对象持久化到数据库中。

    sessionsManager = new NHibernateSessionManager();
        session = sessionsManager.GetSession();
        DALC = new NHibernateDataProvider(session);

        …

        foreach (var pce in pces)
        {
            try
            {
                DALC.UpdateOrAddObject<PortfolioCorporateEntity>(pce);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Could not add Corporate Entity ID " + pce.CorporateEntity.CorporateEntityID.ToString());
            }

        }

这是我的 Nhibernate 数据访问层中的 updateOrAdd 过程,为 10 个对象调用了 10 次。

public void UpdateOrAddObject<T>(T workObject) 
{ 
    using (ITransaction tx = mSession.BeginTransaction) { 
        try { 
            mSession.SaveOrUpdate(workObject); 
            mSession.Flush(); 
            tx.Commit(); 
        } 
        catch (Exception ex) { 
            tx.Rollback(); 
            throw;
        } 
    } 
} 

为了明确一点,会话由调用程序实例化并传递给数据访问层对象,其构造函数如下。

public NHibernateDataProvider(ISession session) 
{ 
    mSession = session; 
} 

这工作正常,除了在异常之后,它说不要在异常后刷新会话。我不知道为什么——事务很好地回滚了,数据库应该准备好接受另一个事务了,不是吗?我做错了什么?

【问题讨论】:

    标签: nhibernate


    【解决方案1】:

    抛出异常后,无法重新使用 NHibernate 会话。 Quoting the documentation:

    If the ISession throws an exception you should immediately rollback the
    transaction, call ISession.Close() and discard the ISession instance.
    Certain methods of ISession will not leave the session in a consistent state.
    

    所以答案是你不能做你想做的事。您需要创建一个新会话并在那里重试更新。

    【讨论】:

      【解决方案2】:

      我清除会话并正常继续

      ISession session = NHibernateHelper.Session; using (ITransaction transaction = session.BeginTransaction()) { try { session.Update(user, user.UserID); transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); session.Clear(); throw new DALException("Cannot update user", ex); } }

      【讨论】:

      • 有效!这是一种保存方式吗?只需使用“session.Clear()”来重新稳定会话?
      • @sh_kamalh 谢谢老兄!我也面临同样的问题,正在寻找这样一个简单的解决方案。
      【解决方案3】:

      感谢您的回复。只是想确保它做得对。你的意思是我的错误处理应该简单地改为:

              foreach (var pce in pces)
              {
                  try
                  {
                      DALC.UpdateOrAddObject<PortfolioCorporateEntity>(pce);
                  }
                  catch (Exception ex)
                  {
                      Console.WriteLine("Could not add Corporate Entity ID " + pce.CorporateEntity.CorporateEntityID.ToString());
      
                      session.Close();
                      session = sessionsManager.GetSession();
                      DALC.Session = session;
      
                  }
              }
      

      看起来这很好用。谢谢。

      【讨论】:

      • 从您发布的内容来看,这似乎可行。这真的取决于你的 DALC 类的实现。
      • 这个解决方案(session.Close/reopen)和上面只用 session.Clear() 的解决方案有什么不同吗?
      猜你喜欢
      • 1970-01-01
      • 2015-07-26
      • 2020-08-09
      • 2020-10-25
      • 1970-01-01
      • 1970-01-01
      • 2020-12-03
      • 1970-01-01
      • 2023-03-23
      相关资源
      最近更新 更多