I have a list of 10 data objects that I want to insert/update to the database using NHibernate. If one throws an exception (say a primary key violation) I want to still insert/update the other 9. I rolled each object operation into its own atomic transaction, and roll back the transaction if there is an exception. Problem is that if a transaction does cause an exception and is rolled back, on the next transaction Nhibernate complains with the error: null id in Nexus.Data.PortfolioCorporateEntity entry (don't flush the Session after an exception occurs)
My main program is simple. It creates a session from a sessionfactory, creates the data access layer, does some work on the data objects and then tries to persist those data objects to the database.
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());
}
}
This is the updateOrAdd procedure in my Nhibernate Data Access Layer, called 10 times for 10 objects.
public void UpdateOrAddObject(T workObject) { using (ITransaction tx = mSession.BeginTransaction) { try { mSession.SaveOrUpdate(workObject); mSession.Flush(); tx.Commit(); } catch (Exception ex) { tx.Rollback(); throw ex; } } }
Just to make the point clear, the session is instantiated by the calling program and passed to the Data Access Layer object, constructor of which is below.
public NHibernateDataProvider(ISession session) { mSession = session; }
This works fine except after the exception, it says don’t flush the session after exception. I’m not sure why – transaction was rolled back nicely and the database should be ready to accept another transaction no? What am I doing wrong?
-
It's not possible to re-use an NHibernate session after an exception is thrown. 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.So the answer is that you can't do what you're trying to do. You need to create a new session and re-try the updates there.
-
Hey Sean,
Thanks for the response. Just wanted to make sure it's done right. What you're saying is that my error handling should be simply changed to:
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; } }Looks like this works just fine. Thanks.
Sean Carpenter : From what you posted, that looks like it will work. It really depends on the implementation of your DALC class. -
I clear the session and it continues normally
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); } }
0 comments:
Post a Comment