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.
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
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.
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