Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate: is it valid to call Session.Flush() before committing a transaction?

I need to execute two operations inside a NHibernate's unit of work: a transactional one (an entity saving) and a not-transactional one.

Since the not-transactional operation cannot be rollbacked, if I save the entity before executing the not-transactional operation (and finally committing the transaction) I still get a transactional behaviour:

  • The operations will be committed only if the two sub-operations execute successfully;
  • If the entity save fails, the not-transactional operation won't be executed;
  • If the not-transactional fails, the entity save will be rollbacked.

The problem: with a code like the following, NHibernate won't execute the actual sql insert until the call to transaction.Commit() (which calls session.Flush() internally):

        using (var transaction = session.BeginTransaction())
        {
            session.Save(entity);
            NotTransactionalOperationBasedOn(entity);

            transaction.Commit(); // the actual sql insert will be executed here
        }

With a code like this, if the Sql Insert fails it's too late: NotTransactionalOperation has been executed. To execute the actual SQL insert before executing NotTransactionalOperation I have to explicity call session.Flush() right before the session.Save():

        using (var transaction = session.BeginTransaction())
        {
            session.Save(entity);
            session.Flush(); // the actual sql insert will be executed here

            NotTransactionalOperationBasedOn(entity);

            transaction.Commit(); 
        }

The code works, but... is it considered a best practice to call session.Flush() before committing the transaction? If not, are there better ways to achieve the same result?

like image 607
Notoriousxl Avatar asked Mar 28 '11 21:03

Notoriousxl


People also ask

What does NHibernate flush do?

Flushing synchronizes the persistent store with in-memory changes but not vice-versa. Note that for all NHibernate ADO.NET connections/transactions, the transaction isolation level for that connection applies to all operations executed by NHibernate!

What is NHibernate session?

NHibernate is an open source object-relational mapper, or simply put, a way to rapidly retrieve data from your database into standard . NET objects. This article teaches you how to create NHibernate sessions, which use database sessions to retrieve and store data into the database.


1 Answers

Flushing means that NHibernate will make sure that all changes are persisted to the DB. That is, it will make sure that all necessary SQL statements are executed. When the transaction fails, and is thus rollbacked, all those changes will be reverted. So, I see no problem in doing that (you must keep in mind however, that your entity might not be in a valid state, since the transaction has failed).

But ... I don't see the problem actually: When the non-transactional procedure fails, what's the problem ? Since the procedure is non-transactional, I guess it has no influence on the information that is held by the database ? Or, what does this code do ?

If it is non-transactional, why can't you do it outside your unit-of-work ?

When the save fails, I guess you'll make sure that not only the transaction is rolled-back, but the exception will be thrown upon the stack as well, until it encounters an error-handler, which probably means that your non-transactional code will not be executed as well:

using( var transaction = session.BeginTransaction() ) 
{
      repository.Save (entity); 

      transaction.Commit();   // error, exception is thrown.
}

NonTransactionalCode (entity); // this line will not be executed, since the exception will be thrown up the stack until a suitable catch block is encountered.
like image 112
Frederik Gheysels Avatar answered Oct 05 '22 11:10

Frederik Gheysels