Nhibernate:处理ITransaction异常,以便新事务可以继续使用相同的ISession

时间:2009-01-29 22:04:46

标签: nhibernate

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

我的主要程序很简单。它从sessionfactory创建一个会话,创建数据访问层,对数据对象进行一些操作,然后尝试将这些数据对象保存到数据库中。

    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; 
} 

除了异常之外,它工作正常,它表示不会在异常后刷新会话。我不确定为什么 - 事务很好地回滚,数据库应该准备接受另一个事务没有?我做错了什么?

3 个答案:

答案 0 :(得分:9)

抛出异常后,无法重用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.

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

答案 1 :(得分:6)

我清除会话并继续正常


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);
    }
}

答案 2 :(得分:0)

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

        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;

            }
        }

看起来这很好用。感谢。