I'm using NHibernate with Fluent NHibernate.
I have code where I start a transaction, then I enter a loop which creates several objects. For each object I check certain conditions. If these conditions are met, then I execute a session.SaveOrUpdate() on the object. At th开发者_如何学JAVAe end of the loop, I issue a commit transaction.
I have a breakpoint set on the session.SaveOrUpdate command, proving that it is never reached (because the conditions have not been met by any of the objects in the loop). Nevertheless, when the transaction is committed, the objects are saved!
I am using an AuditInterceptor and have set a breakpoint in the OnSave method. It is being called, but the stack trace only traces back to the statement that commits the transaction.
There are no objects of any kind that have had SaveOrUpdate executed on them at this point, so cascading doesn't explain it.
Why is NHibernate saving these objects?
From NHibernate ISession.Update thread:
It's the normal and default behavior:
Hibernate maintains a cache of Objects that have been inserted, updated or deleted. It also maintains a cache of Objects that have been queried from the database. These Objects are referred to as persistent Objects as long as the EntityManager that was used to fetch them is still active. What this means is that any changes to these Objects within the bounds of a transaction are automatically persisted when the transaction is committed. These updates are implicit within the boundary of the transaction and you don’t have to explicitly call any method to persist the values.
From Hibernate Pitfalls part 2:
Q) Do I still have to do Save and Update inside transactions?
Save() is only needed for objects that are not persistent (such as new objects). You can use Update to bring an object that has been evicted back into a session.
From NHibernate's automatic (dirty checking) update behaviour:
I've just discovered that if I get an object from an NHibernate session and change a property on object, NHibernate will automatically update the object on commit without me calling Session.Update(myObj)!
Answer: You can set Session.FlushMode to FlushMode.Never. This will make your operations explicit ie: on tx.Commit() or session.Flush(). Of course this will still update the database upon commit/flush. If you do not want this behavior, then call session.Evict(yourObj) and it will then become transient and NHibernate will not issue any db commands for it.
It's to do with the sessions flush mode being FlushMode.Commit (default). When the transaction is committed any changes made to objects within the session are saved and the changes persisted.
There's a FlushMode property on the session that you can set. If you want a readonly transaction specify FlushMode.Manual.
Hope this helps!
精彩评论