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

4 comments
Comments feed for this article
September 8, 2009 at 6:06 pm
Ricardo Peres
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?
September 9, 2009 at 10:54 am
Ricardo Peres
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…
November 10, 2009 at 3:10 pm
felipe
clean code all
September 9, 2009 at 7:46 am
Valeriu Caraulean
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.