R – NHibernate: can I prevent setting of auditing fields from making an object dirty

fluent-nhibernatenhibernate

A common thing that many people do with NHibernate is setting of auditing fields (e.g. CreatedDate, LastModifiedDate) when they save an entity. There are lots of blog posts on how to do this sort of thing using NHibernate events.

This one uses the SaveUpdate event:
http://www.codinginstinct.com/2008/04/nhibernate-20-events-and-listeners.html

This one uses the PreInsert and PreUpdate event:
http://ayende.com/Blog/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx

SaveUpdate feels like a better place to do this, and I'm guessing that this is where most people tend to do it. Here's the problem: I have a one-to-many relationship set up as cascade="save-update". When I save the parent entity, it runs all of the child entities through the SaveUpdate event. But when I set the audit fields there, it just made the child entity dirty! Now it always updates every row in the child collection.

I can move the auditing to PreInsert/PreUpdate, but then I have other problems (I'm using NHibernate Validator for validation, which sets constraints on columns for the schema export, so NHibernate doesn't even get to PreInsert because the audit fields are null and the db columns are not-null columns).

To me the simplest fix would be if there were a way to set the audit fields in SaveUpdate without it making my object dirty. I don't know if that's possible though.

Any suggestions? I'm sure someone has run into this problem.

Best Answer

I would say, SaveUpdate is not the right place, since it runs into this trigger even if it does not save or update the entity.

You need a trigger which is only called when the entity is already declared dirty by NH. This is most probably PreInsert and PreUpdate.

I see the problem you get with the validator. the problem is not that NH thinks that changes on these properties make the entity dirty. The problem is that the validator validates this properties too early.

If you can't parameterize the validator to skip these values, you could probably solve it with this workaround:

  • On SaveUpdate: check if the values are null, set it in this case to make the Validator happy. They are only null when the entity is a new instance, then it will be stored anyway.
  • On PreUpdate and PreInsert: always set it, because the entity had changed.
Related Topic