I made a class that implements ILoadEventListener, and implemented an OnLoad() method (of course — else it wouldn’t even compile). After creating the “new NHibernate.Cfg.Configuration()”, I add it as the documentation says:
configuration.EventListeners.LoadEventListeners = new ILoadEventListener[] {
new MyListener(),
new NHibernate.Event.Default.DefaultLoadEventListener()
};
However, it never seems to get called — I’ve added logging statements to my OnLoad() and set a breakpoint there in the debugger — even when using my app in a way that clearly gets objects from the database using this NHibernate session factory.
What am I missing?
EDIT: I poked around in the source code (the NHibernate event documentation is rather sparse), and found that the event that corresponds to IInterceptor is actually PreLoad, not Load, so I tried using that, and that one does fire. So I can use that for now, but I still don’t really know what preload/load/postload are intended to be.
The documentation on this is practically nonexistent, so maybe this will help a few people:
None of the Load events (Load/PreLoad/PostLoad) will ever fire on an entity that is in the identity cache, even if you
Get,Load, or query for it again.This sort of makes sense if you squint at it just the right way, but it makes for a great deal of frustration due to non-deterministic behaviour, since most of the time, you won’t know whether or not an entity is in the cache. Evidently, these events refer to the process of hydrating an entity as opposed to simply requesting it.
I haven’t tested this theory, but I wouldn’t be surprised if cache hits from the L2 cache also don’t fire Load events, since those entities won’t be hydrated either.
In practice, this means that if you want a particular listener to run on “every” entity, you need to account for the possibility that it was originally a transient instance which was introduced to the session by
Save,Update, etc. In other words, if you implementIPostLoadEventListener, you probably also want to implementIPostInsertEventListenerandIPostUpdateEventListener.This won’t actually change the behaviour – the listener will still only ever run the very first time an entity becomes associated with the session – but at least this guarantees that every entity you can retrieve from the session has been intercepted by that listener. In my case, I was trying to use
PostLoadto inject something into the entity, so this was an acceptable workaround.If you really need the listener to fire every time an entity is retrieved, you either need to use a stateless session (no cache) or evict the entities before loading/querying again.