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 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?
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!
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With