Part II : Implementing Conversation per Business Transaction
Part III (without AOP) : Using Conversation per Business Transaction
Introduction
For this post I’ll use the same example of the Part III but using a real IoC framework (Castle Windsor). To abstract “aspect” the conversation stuff, from its implementation, I will use some custom Attribute defined in uNhAddIns.Adapters assembly. As you can see, downloading the example, there are few classes changed from the previous example, that are the more simple, and less intrusive, implementation of the FamilyCrudModel and, obviously, the implementation of ServiceLocatorProvider.Important
The implementation of “Aspect Conversation-per-BusinessTransaction” presented here is only one of the possible implementations. Gustavo Ringel (blog link not available so far) are working in a real-world example using Conversation-per-BusinessTransaction pattern in a Win-Form application with its implementation of uNhAddIns (the example is available here).“Model” implementation comparison
The new FamilyCrudModel complete implementation is:[PersistenceConversational] public class FamilyCrudModel<TAnimal> : IFamilyCrudModel<TAnimal> where TAnimal : Animal { private readonly IAnimalReadOnlyDao<TAnimal> animalDao; private readonly IFamilyDao<TAnimal> familyDao; public FamilyCrudModel(IDaoFactory factory) { animalDao = factory.GetDao<IAnimalReadOnlyDao<TAnimal>>(); familyDao = factory.GetDao<IFamilyDao<TAnimal>>(); } #region Implementation of IFamilyCrudModel<TAnimal> [PersistenceConversation] public IList<TAnimal> GetExistingComponentsList() { return animalDao.GetAll(); } [PersistenceConversation] public IList<Family<TAnimal>> GetEntirelyList() { return familyDao.GetAll(); } [PersistenceConversation] public Family<TAnimal> GetIfAvailable(int id) { return familyDao.Get(id); } [PersistenceConversation] public Family<TAnimal> Save(Family<TAnimal> entity) { if (entity == null) { throw new ArgumentNullException("entity"); } return familyDao.MakePersistent(entity); } [PersistenceConversation] public void Delete(Family<TAnimal> entity) { if (entity == null) { throw new ArgumentNullException("entity"); } familyDao.MakeTransient(entity); } [PersistenceConversation(ConversationEndMode = EndMode.End)] public void AcceptAll() { } [PersistenceConversation(ConversationEndMode = EndMode.Abort)] public void CancelAll() { } #endregion }Differences, from the previous implementation are:
- don’t need to inherits from any kind of base class.
- the constructor injection is more simple
- the implementation of each method don’t have boiled code
- the class and each persistent-method are marked with a custom attribute
The point(3) is, for example, this comparison:
From the point of view of Conversation-per-Business-Transaction usage that it’s all.
A more deep view
Behind the AOP I’m using, in this example, uNhAddIns.CastleAdapters. For who are familiar with Castle, the CastleAdapters assembly contains:- The TransactionProtectionWrapper and its factory; it is a ISession wrapper to ensure the transaction usage for certain ISession methods. The wrapper is used in all session-handlers implementations available in uNhAddIns (a NoWrappedSessionWrapper implementation is available in uNhAddIns core).
- The AutomaticConversationManagement Castle-Windsor-Facility.
- uNhAddIns-PersistenceConversation-nh-default.config file to use it as an include in the Windsor configuration, if you want use XML configuration.
container.AddFacility<PersistenceConversationFacility>(); var sfp = new SessionFactoryProvider(); sfp.AfterConfigure += ((sender, e) => new SchemaExport(e.Configuration).Create(false, true)); container.Register(Component.For<ISessionFactoryProvider>().Instance(sfp)); container.Register(Component.For<ISessionWrapper>().ImplementedBy<SessionWrapper>()); container.Register(Component.For<IConversationFactory>().ImplementedBy<DefaultConversationFactory>()); container.Register(Component.For<IConversationsContainerAccessor>().ImplementedBy<NhConversationsContainerAccessor>());Note that the class SessionFactoryProvider is the implementation for one-db application and I’m explicit instancing it only because I’m using the AfterConfigure event to create the DB (in production you don’t need to do it).
For who are not familiar with ICurrentSessionContext NHibernate's feature is important to remember that it need a specific NHibernate configuration property:
<property name="current_session_context_class"> uNhAddIns.SessionEasier.Conversations.ThreadLocalConversationalSessionContext, uNhAddIns </property>If you want download the example of this post, as usual, the code is available here.