NHibernate Event Listener Registration With Fluent NHibernate

I’m a huge fan of NHibernate. It has excellent documentation and just makes the whole job of getting things into and out of the database much more enjoyable.  There is a whole series of posts on NHibernate from one of the committers, Ayende.  When Fluent NHibernate (FNH) came out, it was like butter on sliced bread.  FNH makes it even easier to use NHibernate.

Ayende had a great post a while back on how to use Event Listeners. What does an Event Listener do, and furthermore, what does it look like? Listeners give you really low level access to an object just before it gets saved into the database. That allows you at this point to get to both the old state and the new state of an object. You can at this point do any auditing you need to do on the insert, update or delete. I believe you could even block the changes if necessary, but I would probably do that at a higher level before reaching this point.  One of the best uses for listeners is the one presented below, where you can modify the fields for an insert date, a modified date, and the modifying user.

Event Listeners

namespace projectname.infrastructure.app.auditing
{
    using System;
    using System.Security.Principal;
    using System.Web;
    using domain;
    using NHibernate.Event;
    using NHibernate.Persister.Entity;

    public class AuditEventListener : IPreInsertEventListener, IPreUpdateEventListener
    {
        public string get_identity()
        {
            return WindowsIdentity.GetCurrent().Name;
        }

        public bool OnPreInsert(PreInsertEvent event_item)
        {
            Auditable audit = event_item.Entity as Auditable;
            if (audit == null)
            {
                return false;
            }

            DateTime? entered_date = DateTime.Now;
            DateTime? modified_date = DateTime.Now;
            string identity_of_updater = get_identity();

            store(event_item.Persister, event_item.State, "entered_date", entered_date);
            store(event_item.Persister, event_item.State, "modified_date", modified_date);
            store(event_item.Persister, event_item.State, "updating_user", identity_of_updater);
            audit.entered_date = entered_date;
            audit.modified_date = modified_date;
            audit.updating_user = identity_of_updater;

            return false;
        }

        public bool OnPreUpdate(PreUpdateEvent event_item)
        {
            Auditable audit = event_item.Entity as Auditable;
            if (audit == null)
            {
                return false;
            }

            DateTime? modified_date = DateTime.Now;
            string identity_of_updater = get_identity();

            store(event_item.Persister, event_item.State, "modified_date", modified_date);
            store(event_item.Persister, event_item.State, "updating_user", identity_of_updater);
            audit.modified_date = modified_date;
            audit.updating_user = identity_of_updater;

            //insert auditing object here

            return false;
        }

        public void store(IEntityPersister persister, object[] state, string property_name, object value)
        {
            int index = Array.IndexOf(persister.PropertyNames, property_name);
            if (index == -1)
            {
                return;
            }
            state[index] = value;
        }
    }
}

Notice I had to update each value twice. Once on the item and once in the new state. I believe (and I could be wrong) that we update the state so it gets saved to the database and we update the object to match the state of the database so we are in sync. It's a small price to pay for getting this low level access.


Great! Now I have my listeners, but if I run it now, this never gets called. That’s because I haven’t told NHibernate about these event listeners. So I go searching some on the interwebs to learn how to register the listeners. And I come across this. Ayende talks about how to registration in the configuration file in a later post, but with FNH, I register in code.  Hmmm… back to the interwebs…


Then I came across Adam Aldrich’s post on how to register the listeners in code. This is from his post on registration:

NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.EventListeners.PreUpdateEventListeners = 
  new IPreUpdateEventListener[] { new AuditEventListener() };
cfg.EventListeners.PreInsertEventListeners = 
  new IPreInsertEventListener[] { new AuditEventListener() };
_sessionFactory = cfg.BuildSessionFactory();

This is just what I was looking for! Code-based registration. But how do I use FNH to set that up?  That’s where some nice detective work and a fluent interface come in.

Fluent NHibernate Registration of Event Listeners

private void build_factory()
{
    if (nhibernate_session_factory == null)
    {
        nhibernate_session_factory = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2005
                .ConnectionString(c => 
                    c.FromConnectionStringWithKey("db")))
            .Mappings(m => 
                m.FluentMappings.AddFromAssemblyOf<VideoMapping>())
            .ExposeConfiguration(cfg => {
                cfg.SetListener(ListenerType.PreInsert, 
                    new AuditEventListener());
                cfg.SetListener(ListenerType.PreUpdate, 
                    new AuditEventListener());
                })
            .BuildSessionFactory();
    }
}

What FNH has given me here is a way back to the configuration. Now I have full access to do anything I need to do with NHibernate. With it’s discoverability, FNH makes it a joy to use and makes NHibernate even more awesome!


Dear reader, what libraries do you find a joy to use? And why?


Posted 11-20-2009 10:38 PM by Rob Reynolds

[Advertisement]

Comments

Jason wrote re: NHibernate Event Listener Registration With Fluent NHibernate
on 01-20-2011 8:21 AM

Hey nice article Rob. Even though it is over a year old, still good insight for FNH functionality. Thanks

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)