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