I'm revisiting and re-implementing the code that caused me to ask this question about data auditing in NHibernate. However this time, I want go with Sean Carpenter's suggestion and implement the ISaveOrUpdateEventListener (new in NHibernate 2.x)
I want to add a row in a database for each change to each property with the old value and the new so later on in the UI I can say stuff like "User Bob changed Wibble's Property from A to B on 9th March 2009 at 21:04"
What's the best way to compare the object state to work out which of the object's properties have changed?
You can get the loaded state of the object by the following:
public void OnSaveOrUpdate(SaveOrUpdateEvent saveOrUpdateEvent)
{
object[] foo = saveOrUpdateEvent.Entry.LoadedState;
}
And I suppose I could use reflection to work out which properties have changed, but I've been digging around and there doesn't seem to be a matching set of properties to compare. I would've thought there would a GetChangedProperties() method or something.
I could always get the old object from the database as it is and compare it, but that's yet another database hit and would seem heavy handed in this scenario.
What's the best direction to take with this?
P.S. In case it makes any difference, this is an ASP.NET-MVC / S#arp Architecture project.
You could also use the FindDirty method on the Persister to let NHibernate do the comparisons for you:
var dirtyFieldIndexes = @event.Persister.FindDirty(@event.State, @event.OldState, @event.Entity, @event.Session);
foreach (var dirtyFieldIndex in dirtyFieldIndexes)
{
var oldValue = @event.OldState[dirtyFieldIndex];
var newValue = @event.State[dirtyFieldIndex];
// Log values to new "AuditLog" object and save appropriately.
}
I would not know how to achieve what you want with the ISaveOrUpdateListener
interface - you could however take advantage of the fact that IPreUpdateEventListener
and IPreInsertEventListener
interfaces both provide what you need... e.g. do something like this:
public bool OnPreUpdate(PreUpdateEvent evt)
{
string[] names = evt.Persister.PropertyNames;
for(int index = 0; index < names.Length; index++)
{
// compare evt.State[index] to evt.OldState[index] and get
// the name of the changed property from 'names'
// (...)
}
}
and do the same thing for pre insert.
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