One of the challenges I had to overcome when designing BlingBag (my implementation of domain events in C#) was subscribing to the events that it requires on domain entities. You see, other implementations of domain events use a static class that domain entity “calls out” to. My implementation uses plain ole C# event fields to accomplish the same, but without the use of a static class that makes me uncomfortable. Each domain entity has a special event field to which the entity publishes events. Then, the domain event framework responds to published events using matching event handlers.
The only missing piece is “subscription”. How do you subscribe to EVERY domain entity, all the time (so that the events on the entities don’t stay “null”). In my original BlingBag documentation, I suggest that the programmer use domain services that fetch entities from a repository AND THEN initialize them using the initializer (which walks the object graph and subscribes to every domain event contained therein). It works, but it has it’s down-sides. One big problem is when you use a modern ORM like NHibernate that supports “lazy loading”.
Lazy loading makes concepts like domain-driven design’s ”aggregate root” a reality. But, when you have to initialize every entity before it is released into the wild, you run into problems. You either have to accept that the still-lazy proxy collections and reference properties go uninitialized OR you have to disable lazy loading so that there is no such thing as proxy objects.
Well, the solution presented itself today and, as a result, I’m considering changing the BlingBag documentation… NHibernate “Interceptors”. It’s about the simplest solution I could have imagined. It’s also less code to write and extremely re-usable. Check out this code:
An “interceptor” allows us to hook in to different stages of the lifecycle of an entity in the NHibernate session. There are two events that are very useful to us: OnLoad and OnSave. Notice that all I’m doing is initializing the entity before letting it go. By doing it in the load and the save, I’m covering my bases… any entity that’s created by or loaded by the NHibernate session will get initialized… period. No need to initialize entities in ANY other part of the application. Collections and references get queried and populated when NHibernate desires and entities automatically get initialized on-demand. I love it.