10

I'm using NHibernate and looking for a solution that will allow me to audit changes to all fields in entity. I want to be able to create a history table for every entity i.e. Users -> UsersHistory that will have same structure as Users table and additional fields such as operation type (update, delete), userid of user that made change, etc. I don't want to define such class for every entity. I'm looking for something like History<T> (i.e. History<User>) because these entries don't belong to my domain and will only be used to prepare list of changes made to the entity. I also think that it would be better to create inserts to these tables in code rather than creating sql triggers. Basically, I just need to create a copy of record in history table on update or delete and I want the insert to be generated by NHibernate. I will also need to read records from history tables - as I said these tables will consist of entity fields and some common history fields.

I cannot find guidance on how to create such solution. All I can find is adding UserModified, UpdatedTimestamp etc. if I already have such fields on entity. However, I need full history of entity not just the information who last changed the entry.

Thanks in advance for help.

4 Answers 4

16

There is cool, open source audit trail for NHibernate called nhibernate.envers https://bitbucket.org/RogerKratz/nhibernate.envers , so you do not have to reinvent the wheel.

It integrates transparently into NHibernate, no changes to your domain model or mappings.

It's as simple as, adding the reference and call:

var enversConf = new FluentConfiguration(); enversConf.Audit<User>(); nhConf.IntegrateWithEnvers(enversConf); 

whereas nhConf is your NHibernate config object.

For every change on your object a new revision is created, you can ask Envers to retrieve a revision by calling:

var reader = AuditReaderFactory.Get(session); var userInRevOne = reader.Find<User>(user.Id, 1); 

or list all revisions etc. The revision data itself can be enriched with a username, userid, timestamp etc. (whatever you can think off).

EDIT: And it is available at NuGet: http://nuget.org/packages/NHibernate.Envers

Sign up to request clarification or add additional context in comments.

1 Comment

This looks great! I'm currently testing it.
5

I think the best solution is using Event Listeners:

http://darrell.mozingo.net/2009/08/31/auditing-with-nhibernate-listeners/

I wrote something similar to above (modified after finding that blog) except I store the result in XML.

e.g:

public void OnPostUpdate(PostUpdateEvent updateEvent) { if (updateEvent.Entity is AuditItem) return; var dirtyFieldIndexes = updateEvent.Persister.FindDirty(updateEvent.State, updateEvent.OldState, updateEvent.Entity, updateEvent.Session); var data = new XElement("AuditedData"); foreach (var dirtyFieldIndex in dirtyFieldIndexes) { var oldValue = GetStringValueFromStateArray(updateEvent.OldState, dirtyFieldIndex); var newValue = GetStringValueFromStateArray(updateEvent.State, dirtyFieldIndex); if (oldValue == newValue) { continue; } data.Add(new XElement("Item", new XAttribute("Property", updateEvent.Persister.PropertyNames[dirtyFieldIndex]), new XElement("OldValue", oldValue), new XElement("NewValue", newValue) )); } AuditService.Record(data, updateEvent.Entity, AuditType.Update); } 

Audit Service just builds add some additional data such as IP Address, User (if any), was it a system/service update or actioned via a website or user, etc.

Then in my DB i Store the XML like:

<AuditedData> <Item Property="Awesomeness"> <OldValue>above average</OldValue> <NewValue>godly</NewValue> </Item> <Item Property="Name"> <OldValue>Phill</OldValue> <NewValue>Phillip</NewValue> </Item> </AuditedData> 

I also have Insert/Delete listeners.

3 Comments

I wrote sth. similar and while testing I found out that this solution does not work for collections, components etc. so you end up writing handlers for OnPostInsert, OnPostUpdate, OnPostDelete, OnPreUpdateCollection, OnPreRemoveCollection and OnPostRecreateCollection.
There's a work-around for the collections/relationships, I can't find the blog post tho, it was in 2010 tho, was looking at it last week but haven't implemented it yet.
@Phill can you please give me a link to the Insert/Delete listeners.
0

What you are looking for are Event Listeners (unfortunately i cannot link to relevant docs because nhforge.org wiki is experiencing NRE...).

Check Complex NHibernate Auditing

Comments

0

Here's a complete example of how to do this: http://www.shawnduggan.com/?p=89.

Also covered in this post: Audit logging nhibernate

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.