Contents
|
Unit of Work implementation for RavenDBWhen using a framework like NServiceBus there is usually a need to create your own unit of work in order to avoid having to repeat code over an over again in your message handlers. The following demonstrates one approach on how to implement NServiceBus Unit Of Work, for Raven DB. Sharing the sessionThe first thing we need to take care of is sharing the session between our message handler(s) and the actual unit of work implementation.
Instead, begining NServiceBus v3, it is possible to use the new support for child containers To resolve a Raven document session from the container we’ll add the following configuration (StructureMap is used but any one of the other containers except Spring and Unity would work) var store = new DocumentStore { Url = "http://localhost:8080" }; store.Initialize(); ObjectFactory.Configure(c => { c.For<IDocumentStore>() .Singleton() .Use(store); c.For<IDocumentSession>() .Use(ctx => ctx.GetInstance<IDocumentStore>() .OpenSession()); c.For<IManageUnitsOfWork>() .Use<RavenUnitOfWork>(); }); The above code tells the container to create a new IDocumentSession using the lambda specified and the fact that all message processing is done using a child container means that all message handlers processing the message will get the same session instance. Implementing the Unit Of WorkIn RavenDB you need to explicitly call IDocumentSession.SaveChanges() in order to persist your data to the database.
public class RavenUnitOfWork : IManageUnitsOfWork { readonly IDocumentSession session; public RavenUnitOfWork(IDocumentSession session) { this.session = session; } public void Begin() { } public void End(Exception ex) { if (ex == null) session.SaveChanges(); } } Note that we’re taking a dependency on the IDocumentSession and given that the UoW is resolved from the same child container as the handlers we’ll get the same session instance. Raven doesn’t need any special setup so the only thing we need do is call SaveChanges if End() is called and no exception occurred. The final thing we have to do is make NServiceBus use our UoW. We do this by configuring it in the container so that NServiceBus will find it and use it: c.For<IManageUnitsOfWork>() .Use<RavenUnitOfWork>(); What about disposing the session?Again we’re rescued by the child containers and the fact that all single call components that were created in the child container are getting disposed by the main container
when the child container is disposed.
With this in place it is possible to create a very clean message handlers that interact with Raven: public class PlaceOrderHandler : IHandleMessages<PlaceOrder> { readonly IDocumentSession session; public PlaceOrderHandler(IDocumentSession session) { this.session = session; } public void Handle(PlaceOrder message) { session.Store(new Order { OrderId = message.OrderId }); } } Working code please…A working sample can be found over at Andreas Öhlund's github account.
This article was written by Andreas Öhlund and the original blog post can be found here. |