7

I have a problem.

using (var tran = repository.Session.BeginTransaction())
{
    try
    {
        repository.Save(entity);
        tran.Comit();
    }
    catch(Exception)
    {
        tran.Rollback();
        throw;
    }    
}

using (var tran = repository.Session.BeginTransaction())
{
    try
    {
        repository.GetById(id);
        tran.Comit();
    }
    catch(Exception)
    {
        tran.Rollback();
        throw;
    }    
}

When I try to get an entity by ID after exception and tran.rollback() in the first using block, I get an update exception. So NHibernate is trying to update the entity from the first using block in the second using block.

Why? I did the tran.Rollback(). Must I do Session.Clear(), too?

Michael
  • 8,362
  • 6
  • 61
  • 88
Luka
  • 4,075
  • 3
  • 35
  • 61

1 Answers1

15

According to Hibernate's API, when a Hibernate Session throws an exception, you must close the Session and create a new one. Also, when you roll back a Hibernate transaction, you must not later commit it or flush the Session - you must start over in a new Session.

In particular (and this is an implementation detail so don't rely on it), after a rollback, the Hibernate Session still has entities created/modified since the transaction began - Hibernate doesn't go through your entities and revert all changes you made. Therefore, if you roll back the transaction and then flush the Session, Hibernate will commit entity changes that you thought you rolled back. If you are going to play with fire by trying to hack around this behavior (such as by clearing the Session), beware. It's best to just start over with a new Session.

gdj
  • 1,295
  • 10
  • 10
  • 1
    Ok, but my session is contextual managed by structuremap ioc, and is per wcf call. If I dispose the session then I will have errors elsewhere. – Luka Dec 06 '10 at 17:26
  • What exceptions are you getting? Can you try to prevent them? Can you post them here? – gdj Dec 06 '10 at 17:49
  • I am getting GenericAdoException , because I am trying to insert a duplicate value, that must be unique. But that is not the point. I need to know what is the best practice. Until now I have exception handling like the one above. But now, I am seeing that this will not be enough. – Luka Dec 06 '10 at 18:26
  • I can not predict every exception that can happen, I need to have exception handling, and I need to know what must I do so I dont get invalid data in db. – Luka Dec 06 '10 at 18:28
  • 2
    @Luka since you are using a session-per-call it would make sense to have a transaction-per-call (transaction-per-session). This will serve the contextual unit-of-work where each call has no potential side-effects: if a query fails in a call, all db operations that were done in the call will be rollbacked. – Jaguar Dec 07 '10 at 08:29
  • I've spent hours trying to figure out why my rollback wasn't rolling back. Thanks. – Remi Despres-Smyth Jul 11 '17 at 15:09