I configured a PreInsert and PreDelete event listener in NHibernate 2.1. For inserts and deletes on a specific table, I want to write an audit event to a separate auditing table.
public class AuditEventListener : IPreInsertEventListener, IPreDeleteEventListener
{
private static readonly ILog Log = LogManager.GetLogger(typeof(AuditEventListener));
public bool OnPreInsert(PreInsertEvent @event)
{
if (!(@event.Entity is IAuditable))
return false;
return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
true, (@event.Entity as IAuditable));
}
public bool OnPreDelete(PreDeleteEvent @event)
{
if (!(@event.Entity is IAuditable))
return false;
return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
false, (@event.Entity as IAuditable));
}
private bool AuditEvent(ISession session, bool isInsert, IAuditable entity)
{
if (entity is ArticleBinding)
{
if (Log.IsDebugEnabled)
Log.DebugFormat(" audit event ({0}), entity is ArticleBinding", ((isInsert) ? "Insert" : "Delete"));
AddArticleBindingAuditEvent(session, isInsert,
(entity as ArticleTagBinding));
}
return false;
}
private void AddArticleBindingAuditEvent(ISession session,
bool isInsert, ArticleBinding binding)
{
var auditRecord = new AuditArticleBinding()
{
ArticleId = binding.ArticleId,
Action = (isInsert) ? "Add" : "Delete",
LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
? "Unknown"
: Thread.CurrentPrincipal.Identity.Name
};
session.Save(auditRecord);
}
}
I worked through the issue of using the same session, which was causing an exception. Now, all of the code runs fine, and my log statements are hit, but the audit record never gets inserted. Using NHProf, I can see that the INSERT call never occurs.
Why wouldn't the above code cause an INSERT?
I'm currently working on the exact same thing and came up against the same problem. Trying to save a new entity and the INSERT
statement isn't even executed. I found an article about using Pre[Update|Insert]Listeners to audit per record where one comment asks about inserting a new entity and the author replies that a child session is required.
private void AddArticleBindingAuditEvent(ISession session,
bool isInsert, ArticleBinding binding)
{
var childSession = e.Session.GetSession(EntityMode.Poco);
var auditRecord = new AuditArticleBinding()
{
ArticleId = binding.ArticleId,
Action = (isInsert) ? "Add" : "Delete",
LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
? "Unknown"
: Thread.CurrentPrincipal.Identity.Name
};
childSession.Save(auditRecord);
childSession.Flush();
}
Another reference for you (which I found today) is Auditing with NHibernate Listeners. It gives a full example on inserting a new audit log but uses the Post listeners and is non-entity specific (doing pretty much the same as me with the persister to find the changed values). I'm not sure what the benefit of this is over using the Pre listeners.
And as a 'just-in-case', you need to ensure that you are hooking the event listener up to your configuration:
var eventListener = new AuditEventListener();
config.SetListener(ListenerType.PreInsert, eventListener);
config.SetListener(ListenerType.PreDelete, eventListener);
Full disclosure: I'm pretty new to NHibernate so if there's anything that I missed or could do better, please let me know. The above method works for me in that my record is successfully inserted into the database, but it does fail in certain instances. Although I'm almost certain this is specific to my application (of which I'm new to the codebase, so still working things out)
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