One of the areas where NHibernate really shines is it’s high extensibility features. The NHibernate API provides a massive amount of interfaces that can be implemented for your own custom extension pleasure.
For me this is a nice change as opposed to the many sealed API’s put out by the Redmond collective (WCF being the exception, the Entity Framework confirming the rule).
Anyhow, with great power comes great responsibility. Today I encountered a rather difficult problem with NHibernate that could have been easily prevented by reading the documentation (note to self: use the CTRL-Q shortcut of Resharper more often).
We have implemented an interceptor for automatically configuring audit information as described by this great post from Ray Houston.
public class AuditInformationInterceptor : EmptyInterceptor { Boolean OnSave(Object entity, Object id, Object[] state, String[] propertyNames, IType[] types) { // Implementation } Boolean OnFlushDirty(Object entity, Object id, Object[] currentState, Object[] previousState, String[] propertyNames, IType[] types) { // Implementation } }
The mistake we made is that we manipulated the audit information of the entity directly in the OnSave and OnFlushDirty methods. This only became apparent when saving an aggregate root with his child entities. Everything worked fine until we wanted to persist one of the child entities that should have been a piece of cake but turned out to be the messenger of trouble. NHibernate refused to perform an INSERT statement, but instead threw an UPDATE statement at us.
After some debugging we found out that the audit information should have been manipulated through the state and currentState arguments of the OnSave and OnFlushDirty methods respectively.
The documentation of the OnSave method clearly states:
The interceptor may modify the state, which will be used for the SQL INSERT
and propagated to the persistent object
Lesson relearned.
I’m off, reading some docs. Until next time.
I had exactly the same situation recently. I am using ActiveRecord and I was trying to use BeforeSave / OnFlushDirty overrides to set some data in my objects, e.g. creation date, but the changes were not saved to DB. I found your post and after reading it I was like “aah, that’s why!” – I was changing the object, and as you wrote, I should rather change the state/currentState collections. Many thanks!
Actually I’ve put this on my blog in order to prevent myself from making the same mistake twice :-). I’m glad it also worked for you.
Hello Jan, I’ve done some deep search about NH Interceptor. Here you can find the last part http://blog.scooletz.com/2011/02/22/nhibernate-interceptor-magic-tricks-pt-5/