Try fast search NHibernate

07 January 2009

Aspect Conversation-per-BusinessTransaction

Part I : Conversation-per-Business-Transaction
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:
  1. don’t need to inherits from any kind of base class.
  2. the constructor injection is more simple
  3. the implementation of each method don’t have boiled code
  4. the class and each persistent-method are marked with a custom attribute
I can avoid the point (4) depending on the AOP framework features, using Castle, for example, I can inject the behavior using XML or Fluent-Interface-Configuration.
The point(3) is, for example, this comparison:
ImplComparison
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.
If you want use Fluent-Castle-configuration a possible implementation is:
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.


kick it on DotNetKicks.com


06 January 2009

Using Conversation per Business Transaction

The point I leave the pattern, in previous post, was its implementation.
Before show how use it with AOP, I think is better to show how it work because my AOP implementation is only one of the possible implementations and you can write yours (and hopefully share it).

Introduction

In this post, you will see a persistent-conversation which theory was introduced in here. Remember that what I want do is abstract the persistent-conversation-handling from the DAO/Repository implementation. The persistence-layer, I’ll use, is NHibernate2.1.0 (trunk) and the UoW is the NHibernate’s session. The use of NH2.1.0 mean that you must know this, by the way in this example I’ll show how use the conversation avoiding any kind of DynamicProxy, IoC and AOP framework (I hope you would use one).
Even if the target of the example is a win-form or WPF application I don’t want spent a single second writing a GUI so you will see a console application.

The example core

To understand how use the pattern implementation you should study two implementations: PersistenceConversationalModel, FamilyCrudModel
Let me show only one method:
public IList<TAnimal> GetExistingComponentsList()
{
try
{
using (GetConversationCaregiver())
{
return animalDao.GetAll();
}
}
catch (Exception e)
{
ManageException(e);
throw;
}
}

The real action here is animalDao.GetAll(); . The action is enclosed in a “Resume” – “Pause”. In the try-catch I’m discarding the persistence conversation in case of an exception.
If you don’t use AOP you must enclose all DAOs/Repository actions with the same structure (obviously you can call more than one action between  “Resume” – “Pause”).
The two methods to End or Abort the conversation are respectively:
public void AcceptAll()
{
try
{
EndPersistenceConversation();
}
catch (Exception e)
{
ManageException(e);
throw;
}
}

public void CancelAll()
{
try
{
AbortPersistenceConversation();
}
catch (Exception e)
{
ManageException(e);
throw;
}
}

From the point of view of Conversation-per-Business-Transaction usage that it’s all.

A more deep view

To have a more deep view, and understand what a possible AOP implementation must do (remember that you have one implemented and usable here), I must explain what are doing the PersistenceConversationCaregiver each time you call the method GetConversationCaregiver().


   1:         private class PersistenceConversationCaregiver : IDisposable
   2:         {
   3:             private readonly ConversationEndMode endMode;
   4:             private readonly PersistenceConversationalModel pcm;
   5:  
   6:             public PersistenceConversationCaregiver(PersistenceConversationalModel pcm, ConversationEndMode endMode)
   7:             {
   8:                 this.pcm = pcm;
   9:                 this.endMode = endMode;
  10:                 string convId = pcm.GetConvesationId();
  11:                 IConversation c = pcm.cca.Container.Get(convId) ?? pcm.cf.CreateConversation(convId);
  12:                 pcm.cca.Container.SetAsCurrent(c);
  13:                 c.Resume();
  14:             }
  15:  
  16:             #region Implementation of IDisposable
  17:  
  18:             public void Dispose()
  19:             {
  20:                 IConversation c = pcm.cca.Container.Get(pcm.GetConvesationId());
  21:                 switch (endMode)
  22:                 {
  23:                     case ConversationEndMode.End:
  24:                         c.End();
  25:                         break;
  26:                     case ConversationEndMode.Abort:
  27:                         c.Dispose();
  28:                         break;
  29:                     default:
  30:                         c.Pause();
  31:                         break;
  32:                 }
  33:             }
  34:  
  35:             #endregion
  36:         }

In the constructor (form line 6 to 14):
line 10 : I’m getting the conversationId from the “model” instance. The conversationId is a Guid in a string and the “model” is the conversationId-holder.
line 11: I’m getting the existing conversation, from the container, or I create a new one.
line 12: I’m setting the conversation as the current conversation.
line 13: I’m starting or resume the conversation.
In the dispose (from line 18 to 33):
line 20: I’m getting the conversation (it must exists)
line 30: I’m pausing the conversation.
To End or Abort the conversation the implementation is:
protected void EndPersistenceConversation()
{
IConversation c = cca.Container.Get(GetConvesationId());
if(c!=null)
{
c.Resume();
c.End();
}
}

protected void AbortPersistenceConversation()
{
IConversation c = cca.Container.Get(GetConvesationId());
if (c != null)
{
c.Abort();
}
}
Note the Resume before the End of the conversation; to be ended the conversation must be active.
The GetConvesationId() have no secrets:
protected virtual string GetConvesationId()
{
if (conversationId == null)
{
conversationId = Guid.NewGuid().ToString();
}
return conversationId;
}
What is more important, perhaps, is the ManageException method:
protected virtual void ManageException(Exception e)
{
IConversation c = cca.Container.Unbind(conversationId);
if (c != null)
{
c.Dispose();
}
}
Here I’m unbinding the conversation from the container and disposing the conversation. In term of NHibernate this mean the Rollback of the transaction and the dispose of the session. After this operation you can continue working in the same “Model” instance, what you must know is that you will use a new NHibernate-session.

The Example

The example show how the pattern work in tow cases:
  1. A simulation of an input in one Form
  2. A simulation of an input in two opened Form
If you download the code you can see a Diagram in each “layer”.
To have fun, writing the example, I have implemented a HomeMadeServiceLocator and I hope it can be useful to who are scared by IoC, Dependency Injection and AOP words.
The code of the example is available here.
If you have some question, about the example, feel free to ask.


kick it on DotNetKicks.com


22 December 2008

Implementing Conversation per Business Transaction

In the previous post I talked about the theory behind the pattern. This post is about its implementation.

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:

The big picture

IConversation
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

ConversationImpl1
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.
ConversationImpl2
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
To be clear, about the advantage of an implementation of ICurrentSessionContext, take a look on how may appear an implementation of a simple DAO
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.

Conclusion

The next step, perhaps before a working example, will be “Aspect Conversation-per-BusinessTransaction” to have the “Full cream” working together. If you are inpatient you can see it by your self.


kick it on DotNetKicks.com