One usually does not need to call Flush() if he uses transaction. Flush() is useful
inside a transaction when you want some changes to propagate to the database immediately (to force a trigger, for example) so that you can do a load on some other things that depends on the trigger having been fired. If I have to boil it down to a rule, it is this:
Quote:
Do not call Flush() outside of a transaction; unless you are not using transactions
Here is a very typical block of code that you will see in many applications:
Code:
ISession s = OpenSession();
ITransaction tx = s.BeginTransaction();
try
{
Thing thing = s.Get<Thing>(thingId);
// Change some property about the thing
s.Save(new OtherThing());
tx.Commit();
}
catch (Exception)
{
tx.Rollback();
// Do whatever else you need to do
}
finally
{
// s.Flush();
s.Close();
}
Note that the call to Flush() is commented out. This is perfectly acceptable. Consider the call to Flush() is now uncommented. Here is a possible sequence of events:
- Session is opened and transaction begun
- You loaded "thing" and made some changes to its properties. At this point, nothing is pushed to the database yet
- You created an "OtherThing" and saved it, but the save failed for some reason and an exception is thrown
- You arrived at the catch-block and the transaction is rolledback
- The finally-block is run and the session is flushed... uh-oh
- NHibernate sees that the "thing" has changed state, so it pushes the change to the database
- You close the session, and the "thing" is changed forever
Ironically, had you called Flush() after you changed the "thing" (which is inside the transaction), the change would not have persisted.
A much better and concise way to write the equivalent of the above code block is as follows:
Code:
try {
using (ISession s = OpenSession())
using (ITransaction tx = s.BeginTransaction()) {
Thing thing = s.Get<Thing>(thingId);
// Change some property about the thing
s.Save(new OtherThing());
tx.Commit();
}
}
catch (Exception ex) {
// Do what you need to do
}
If an exception is thrown inside the using blocks, the transaction is automatically rolled back and session is automatically closed. With a web app, you need to manage the session and the transaction carefully so that you either commit or roll back the transaction; and do not call Flush() afterwards.