Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving new entity in PreInsert/PreDelete event listener doesn't persist to database

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?

like image 973
Chris J Avatar asked Apr 12 '11 21:04

Chris J


1 Answers

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)

like image 108
Jonathon Bolster Avatar answered Nov 03 '22 22:11

Jonathon Bolster