我有一个包含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;
}
除了异常之外,它工作正常,它表示不会在异常后刷新会话。我不确定为什么 - 事务很好地回滚,数据库应该准备接受另一个事务没有?我做错了什么?
答案 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;
}
}
看起来这很好用。感谢。