Clean code: Register additional event listeners in NHibernate

“why is this a problem?” may ask you…

Let’s review the ways that NHibernate lets you register your own event listeners. You can do it in configuration file:

<listener class=”NHTest.Listeners.CustomSaveEventListener, NHTest” type=”save” />

… or in code:

Configuration cfg = new Configuration();
cfg.EventListeners.SaveEventListeners =
    new ISaveOrUpdateEventListener[] {new CustomSaveEventListener() };

Nice, so far…

It’s not if you want to add a listener, not to replace them. Both registrations are just replacing default event listeners with your own implementations. Very often it’s not want you want!

In our case, we want default listeners do the job and just add few our own listeners to run the business. No problem, let’s code:

var listeners = configuration.EventListeners;
listeners.SaveEventListeners =
    new List<ISaveOrUpdateEventListener>(listeners.SaveEventListeners)
    {new CustomSaveEventListener()}
    .ToArray();

 

Since I wrote that code some day I hated it. Too verbose, too obscure, hard to read & understand. But event registration infrastructure doesn’t offer an easy and simple way to add a listener. Few times I tried to come with a nice solution for that, even tried to modify NH’s code.

Today, I’ve done it:

configuration.AddListener(el => el.SaveEventListeners, new CustomSaveEventListener());

Some expression’s magic and we end up with a very clean & readable code.

Implementation:

public static class NHibernateConfigurationExtensions
{
    public static void AddListener<TListener>(
        this Configuration configuration,
        Expression<Func<EventListeners, TListener[]>> expression,
        TListener listenerImpl)
    {
        var propertyInfo = ReflectionHelper.GetProperty(expression);
        var existentListeners = (TListener[]) propertyInfo.GetValue(configuration.EventListeners, null);
        var newListeners = new List<TListener>(existentListeners) { listenerImpl }.ToArray();
        propertyInfo.SetValue(configuration.EventListeners, newListeners, null);
    }

    public static void AddListeners<TListener>(
        this Configuration configuration,
        Expression<Func<EventListeners, TListener[]>> expression,
        IEnumerable<TListener> listeners)
    {
        foreach (var listener in listeners)
        {
            configuration.AddListener(expression, listener);
        }
    }
}
Have a nice day...
Advertisement
  1. #1 by Ricardo Peres on September 8, 2009 - 18:06

    Interesting. Is it possible to cancel the default processing using an event listener?
    For example, suppose I’m loading a list of entities, but I want to remove some of them from the list, for example, because the current user is not authorized to access them. Is this possible?

    • #2 by Valeriu Caraulean on September 9, 2009 - 07:46

      I’m not sure you can achieve that by using an event listener.

      What about “removing” items from a list before making it available to the rest of application I think it’s not a good idea: you’re loading thousands of rows from database to filter only hundreds of it? Why don’t do that directly in database?
      From the top of my mind you can use two things:
      – using filters & setting them to filter rows
      – enrich your queries, so that you’ll get back from database only relevant rows
      For second approach take a look how it’s done in Rhino.Security (his API). It’s a great example how you can create a flexible security infrastructure with NHibernate.

  2. #3 by Ricardo Peres on September 9, 2009 - 10:54

    Thanks for your reply!
    Yes, I know what you mean, and I wouldn’t do it in real-life scenarios, I just wanted find out if it can be done. I came up to interceptors, and the IInterceptor.OnLoad event, but I can’t cancel it…

  3. #4 by felipe on November 10, 2009 - 15:10

    clean code all

  4. #5 by Yong Bursey on February 1, 2011 - 03:15

    Hi there! I just wish to give a huge thumbs up for the great data you may have right here on this post. I might be coming again to your weblog for extra soon.

  1. mazhou blog

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.