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


我有一个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; 
} 

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


8436
2018-01-29 22:04


起源



答案:


抛出异常后,无法重新使用NHibernate会话。 引用文档

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.

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


9
2018-02-01 22:27





我清除会话并继续正常


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


6
2017-09-18 19:30



作品!这是一种保存方式吗?只需使用“session.Clear()”来重新稳定会话? - dataCore
@sh_kamalh谢谢你的队友!我也面临同样的问题,并寻找这样一个简单的解决方案。 - shahjahan


答案:


抛出异常后,无法重新使用NHibernate会话。 引用文档

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.

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


9
2018-02-01 22:27





我清除会话并继续正常


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


6
2017-09-18 19:30



作品!这是一种保存方式吗?只需使用“session.Clear()”来重新稳定会话? - dataCore
@sh_kamalh谢谢你的队友!我也面临同样的问题,并寻找这样一个简单的解决方案。 - shahjahan


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

        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;

            }
        }

看起来这很好用。谢谢。


0
2018-02-02 16:11



从您发布的内容来看,它看起来会起作用。这实际上取决于您的DALC类的实现。 - Sean Carpenter
这个解决方案(session.Close / reopen)和上面的解决方案只有session.Clear()有什么不同吗? - dataCore