Introduction
If you read my blog you know how much I like “Program to an interface and not to an implementation”; this mean that first of all you will see interfaces instead of classes.One of the targets of this implementation is maintain the same style of the others “Session Easier” of uNhAddIns; this mean:
- I will end in an implementation of ICurrentSessionContext.
- the session will be wrapped by a Dynamic-Proxy to ensure transaction-protection.
- Dynamic-Proxy provider and AOP stuff will be implemented in separate assembly (as you can see in CastleAdapters and LinFuAdapters)
- Web contexts will be implemented in a separate assembly.
The big picture
IConversation
Is a representation of a “Persistence conversation” I showed in the previous post. In addition there are some events.ConversationException
Is the base exception for “all” conversation implementations.IConversationFactory
So far I “don’t know” which will be the real implementation of the “Persistence conversation” (may be ADO.NET, may be NHibernate); its factory is needed.IConversationContainer
As I said, in a IM, we may have more than one conversation happening at the same time. This fact still true for “Persistence conversation”. For a winForm application it is pretty easy to understand because, in the same application (mean same Thread), the user may activate more than one independent business-transaction. In a WEB application it still true because the user may open more than one browser-tab, in the same browser instance sharing the same HttpSession, activating various independent business-transaction (or better he sure hope that each tab are working in a independent persistence context).IConversationsContainerAccessor
In my application I need something to access to the ConversationContainer instance (a sort of a specific ServiceLocator for ConversationContainer implementation) especially if I want allow the use of a formal DI container.The implementation
AbstractConversation
Encapsulation of the behavior of a generic Persistence conversation. The implementation, basically, define that each conversation have an ID defined at the moment of its creation, implements the EqualityComparer based on the ID, implements the Disposable pattern and implements the events managements. The real hard work will be done in the five abstract methods: DoStart, DoPause, DoResume, DoEnd, DoAbort.NhConversation
At the end, I have arrived to the Persistence Conversation implemented for NHibernate. The base behavior was described at the end of the previous post, what I would explain here is the role of the two injected fields: factoriesProvider, wrapper.The factoriesProvider is an implementation of ISessionFactoryProvider that is the class responsible to provide all ISessionFactory needed by our application. In uNhAddIns you have two available implementations to work with one or more than one RDBMS, respectively SessionFactoryProvider and MultiSessionFactoryProvider. In the MultiSessionFactoryProvider you can inject an instance of IMultiFactoryConfigurator or use the default implementation.
The wrapper is an implementation of ISessionWrapper. The main target of a wrapped session is the interception of the Close and Dispose. In uNhAddIns the base implementation are doing something more: it are ensuring that you are working applying a best practice for session&transaction management. The implementation of ISessionWrapper is the responsible to wrap a session and recognize a wrapped instance. In uNhAddIns, so far, you have two available implementations using Castle.DynamicProxy2 and LinFu.DynamicProxy. Obviously you can write your own implementation without transaction protection.
NHibernate Conversation solved, now the implementation of the others interfaces to work with Conversation-per-Business-Transaction pattern.
DefaultConversationFactory
Nothing special to say, its implementation is trivial.AbstractConversationContainer
Encapsulation of the behavior of the conversation container. What I’m not defining here is which will be the real context where the container are running, that mean where all conversation will be stored and where will be stored the current conversation id. The Store of conversation is a Dictionary<string, IConversation> where the key is the ConversationId and the value is an instance of an started conversation.ThreadLocalConversationContainer
This is the implementation of the ConversationContainer for a winForm, or WPF, application. As you can see the CurrentId and the Store are two ThreadStatic fields.ThreadLocalConversationalSessionContext
As I said at the begin of this post the “story” end when I have an implementation of ICurrentSessionContext. The implementation, at this point, is trivial but the advantage of an implementation of ICurrentSessionContext is really big:- Your DAOs/Repositories are wired only with NHibernate and nothing more than its SessionFactory.
- You can change the strategy of session-handling without change absolutely nothing in your DAOs/Repositories
public class SillyDao : ISillyDao { private readonly ISessionFactory factory; public SillyDao(ISessionFactory factory) { this.factory = factory; } public Silly Get(int id) { return factory.GetCurrentSession().Get<Silly>(id); } public IList<Silly> GetAll() { return factory.GetCurrentSession().CreateQuery("from Silly").List<Silly>(); } public Silly MakePersistent(Silly entity) { factory.GetCurrentSession().SaveOrUpdate(entity); return entity; } public void MakeTransient(Silly entity) { factory.GetCurrentSession().Delete(entity); } }
As you can see I’m using factory.GetCurrentSession() this mean that my DAOs don’t know who and how the session is provided; don’t know nothing about uNhAddIns, don’t know nothing about conversation management.