R – Nhibernate: Handling an ITransaction Exception So That New Transactions Can Continue with same ISession

nhibernate

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>(T workObject) 
{ 
    using (ITransaction tx = mSession.BeginTransaction) { 
        try { 
            mSession.SaveOrUpdate(workObject); 
            mSession.Flush(); 
            tx.Commit(); 
        } 
        catch (Exception ex) { 
            tx.Rollback(); 
            throw;
        } 
    } 
} 

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?

Best Answer

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.