Try fast search NHibernate

Showing posts with label session management. Show all posts
Showing posts with label session management. Show all posts

17 September 2009

Configure SessionFactory Providers

This is about a pending task from long time ago… sorry for those waiting for it.

In the AOP example of CpBT you probably saw a class named SessionFactoryProvider; that class was wrote before CpBT and it can be used in others Contexts (ICurrentSessionContext).

ISessionFactoryProvider

The ISessionFactoryProvider is the contract for the implementation responsible for providing NHibernate’s sessionFactory/ies (big fantasy, no?). ISessionFactoryProvider implements IEnumerable<ISessionFactory> and its more important method is:

ISessionFactory GetFactory(string factoryId);

The parameter factoryId is the name you gave to the session-factory configuration:

<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2">
<
session-factory name="Domain_A">

The parameter factoryId, in this case, should be “Domain_A”.

In uNhAddIns there are two implementations: SessionFactoryProvider and MultiSessionFactoryProvider.

IConfigurationProvider

Both implementations, SessionFactoryProvider and MultiSessionFactoryProvider, have a dependency to an implementation of IConfigurationProvider. The responsibility of an IConfigurationProvider is: provide the set of configured NHibernate’s configurations (again big fantasy).

The contract is:

public interface IConfigurationProvider
{
IEnumerable<Configuration> Configure();
event EventHandler<ConfiguringEventArgs> BeforeConfigure;
event EventHandler<ConfigurationEventArgs> AfterConfigure;
}

In the implementation the BeforeConfigure event should be fired just before call configuration.Configure() of each configuration. You can use the event, for example to use the new NHibernate fluent configuration, or to change some property by code, or to set the ByteCodeProvider, or to use the Fluent-NHibernate configuration way, and so on.

The AfterConfigure event should be fired just after call configuration.Configure() of each configuration. You can use the event to add mappings, create the schema, or integrate it with NHibernate.Validator, or anything else you can do after have a configured NHibernate configuration.

The implementation of Configure method should return instances of NHibernate’s configurations ready to call the BuildSessionFactory method.

In uNhAddIns there are two implementations: DefaultSessionFactoryConfigurationProvider and DefaultMultiFactoryConfigurationProvider.

DefaultSessionFactoryConfigurationProvider

Nothing special to say; basically I can resume its behavior as:

var cfg = new Configuration();
cfg.Configure();

DefaultMultiFactoryConfigurationProvider

For multiple session factories what we need are the names of nhibernate’s config files. The configuration is through appSettings:

<configuration>
<
appSettings>
<
add key="nhfactory.WhatEverYouWant" value="AppApersistence.cfg.xml" />
<
add key="nhfactory.TheOther.NH.configFileName" value="AppBpersistence.cfg.xml" />

As you can see there is only a constant part, the “nhfactory”. The DefaultMultiFactoryConfigurationProvider will iterate all settings looking for those have the key starting with “nhfactory” (what follow is important only for you). The value is the name of the file with each NHibernate configuration. As said above what will be important is the session-factory’s name you will specify inside each configuration.

Custom configuration provider

Obviously you can implement your own configuration provider and use it to inject the behavior to a ISessionFactoryProvider (no matter if you will inject it manually or using a DI framework). You can start your own implementation from scratch or inheriting from AbstractConfigurationProvider or inheriting from one of defaults. An example may look as:

public class MyConfigurationProvider : DefaultMultiFactoryConfigurationProvider
{
public MyConfigurationProvider()
{
AfterConfigure += ConfigureCache;
}

private static void ConfigureCache(object sender, ConfigurationEventArgs e)
{
e.Configuration.QueryCache().ResolveRegion("SearchStatistic")
.Using<TolerantQueryCache>().AlwaysTolerant();
}
}

Configuring your DAOs/Repository for multiple DB

This is the real target of this post. In this example I will show an example using Castle.Windsor.

The start point is that you have, at least, two sessions factories configurations in two files (each one will look as an hibernate.cfg.xml you saw in many examples).

The first

    <session-factory name="Domain_A">

and the second

    <session-factory name="Domain_B">

The container configuration through XML should look like

 <facilities>
<
facility id="factorysupport"
type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
</
facilities>

<
component id="sessionFactoryProvider"
service="uNhAddIns.SessionEasier.ISessionFactoryProvider, uNhAddIns"
type="uNhAddIns.SessionEasier.MultiSessionFactoryProvider, uNhAddIns"/>

<
component id="domain_a.sessionFactory"
type="NHibernate.ISessionFactory, NHibernate"
factoryId="sessionFactoryProvider"
factoryCreate="GetFactory">
<
parameters>
<
factoryId>Domain_A</factoryId>
</
parameters>
</
component>

<
component id="domain_b.sessionFactory"
type="NHibernate.ISessionFactory, NHibernate"
factoryId="sessionFactoryProvider"
factoryCreate="GetFactory">
<
parameters>
<
factoryId>Domain_B</factoryId>
</
parameters>
</
component>

<
component id="domain_a.dao.AnEntity"
service='MyCompany.Data.IDao`1[[MyCompany.AnEntity, MyCompany]], MyCompany.Data'
type='MyCompany.Data.Nh.EntityDao`1[[MyCompany.AnEntity, MyCompany]], MyCompany.Data.Nh'>
<
parameters>
<
factory>${domain_a.sessionFactory}</factory>
</
parameters>
</
component>

<
component id="domain_a.dao.AnotherEntity"
service='MyCompany.Data.IDao`1[[MyCompany.AnotherEntity, MyCompany]], MyCompany.Data'
type='MyCompany.Data.Nh.EntityDao`1[[MyCompany.AnotherEntity, MyCompany]], MyCompany.Data.Nh'>
<
parameters>
<
factory>${domain_b.sessionFactory}</factory>
</
parameters>
</
component>

The are two DAOs each one pointing to a different session factory.

If you prefer the configuration by code it should look as:

private const string Domain_A = "Domain_A";
private const string Domain_B = "Domain_B";
private const string SessionFactoryProviderComponentKey = "sessionFactoryProvider";

...

public void ConfigurePersistence()
{
container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();

container.Register(Component.For<ISessionFactoryProvider>()
.Named(SessionFactoryProviderComponentKey)
.ImplementedBy<MultiSessionFactoryProvider>());

RegisterSessionFactoryFor(Domain_A);
RegisterSessionFactoryFor(Domain_B);

RegisterEntityDao<AnEntity>(Domain_A);
RegisterEntityDao<AnotherEntity>(Domain_B);
}

private void RegisterSessionFactoryFor(string sessionFactoryName)
{
container.Register(
Component.For<ISessionFactory>()
.Named(GetSessionFactoryProviderKey(sessionFactoryName))
.Configuration(Attrib.ForName("factoryId").Eq(SessionFactoryProviderComponentKey),
Attrib.ForName("factoryCreate").Eq("GetFactory"))
.Parameters(Parameter.ForKey("factoryId").Eq(sessionFactoryName)));
}

private void RegisterEntityDao<T>(string sessionFactoryName) where T : class, IGenericEntity<int>
{
container.Register(
Component.For<IDao<T>>().ImplementedBy<EntityDao<T>>()
.Parameters(
Parameter.ForKey("factory")
.Eq("${" + GetSessionFactoryProviderKey(sessionFactoryName) + "}")));
}

private static string GetSessionFactoryProviderKey(string sessionFactoryName)
{
return sessionFactoryName + ".sessionFactory";
}

Acknowledgments

Special thanks to those customers allow me to share the knowledge they paid.

09 September 2009

NHibernate in WinForm: coupled

After ten months of public CpBT I still seeing people fighting to find a pattern to manage the NHibernate session in WinForm/WPF.

I’m not sure but perhaps one reason is ours uncoupled examples. So far, in the examples available in uNhAddIns, we have used IoC/DI and AOP, MVP/MVVM/MVC, DAO/Repository trying to show a more real and uncoupled example of a possible application. In this post I have tried to show that Dependency Injection is not the devil implementing a “10 minutes container” (here the code of the container and here the code of its configuration).

This time I’ll try to make a WinForm application, more coupled as possible… perhaps is more easy to uncouple a coupled application than couple an uncoupled.

Targets / Warning

The main target is allow to beginners an easy usage of debugger to follow the execution. I’ll try to avoid any kind of external framework other than NHibernate, NHibernate.Validator and WinForm, avoid any kind of architectural abstraction and so on. In practice the result should be a monolithic WinForms application with object binding.

I know that the final result is not a good example about “how create an WinForm application with NHibernate” but perhaps it will be useful to new users coming from VB6 and/or DataBinding applications.

Preparing the environment

After download the example (see below) what you need is only VisualStudio2008 and MsSQL-EXPRESS. The zip contains NHibernate 2.1.0GA and its dependencies and the last available NHibernate.Validator 1.2.0.

Before run the application you need to create an empty DataBase is your MsSQL-EXPRESS named “Chinook”. You can create it using SQL Server Management Studio Express or using command line:

C:\>sqlcmd -S YourMachine\SQLEXPRESS
1> create database Chinook
2> go

If you want change the DB name remember that you will need to change the connection string in the App.config file:

<property name="connection.connection_string">
Server=(local)\SQLEXPRESS;initial catalog=Chinook;Integrated Security=SSPI
</property>

Quick Show: NHibernate’s session, the Unit of Work

During the first show have a look in the bottom side to see when the hit to DB happens.




The first is a simple input form with object binding an error info; as you saw pressing “OK” two queries are executed: the first to retrieve the high value of HighLow for the Artist entity and the second to insert the new Artist.

In the second part I’m showing two instances of the same form. In instance on the right side, pressing “Add” I’m creating a new instance of the form used for the first part but this time pressing the button “Ok” nothing happen with the DB because the “Jethro Tull” artist is part of a different UnitOfWork (the “Artist Form” is sharing the same NHibernate’s session with “Artists Form” in the right). When I click “Refresh” on the left form the application go to DB to retrieve the refreshed list but nothing change because the UnitOfWork in the right was not committed. When I try to click “Refresh” on the right form a message is showed because there are pending operations in the UoW (the NHibernate’s session is dirty). Finally I’m committing the work of the right form and you can see the hit to DB to insert “Jethro Tull”; at this point the refresh of the left form will find the new Artist instance.

Full Object binding and IDataErrorInfo support

In this show you will see entities implementing INotifyPropertyChanged/IDataErrorInfo and child collection supporting BindingList<T>.




The relationship between Album and Tracks is a classic Master-Details and, as you can see, all is working as data-binding.

Conclusion

If you need some explication about the code, please strictly related to NHibernate usage, you can leave a comment here or you can use the nh-users group.

Download sources!


Another download place is here.

P.S. test everything using only F5 was not so fun for me.

23 August 2009

NHibernate Perfomance: Analisys

In this post I will show the results of the previous post from another point of view hoping it would be useful to Gergely Orosz to understand how work with NHibernate to have better performance for his test (in that post you can download the original code).

The environment

Pentium D840, 3GB ram, winXP, MsSQL2008Express, .NET3.5, NHibernate2.1.0GA.

The domain is the same:

domain

where each Company has 24 Employees and each employee has 24 Reports (save a company mean save 601 entities).

Storing data

The StoreData test is basically a bulk insertion, of the domain, importing data from XML. To have better performance, in bulk inserts, there are basically two “tricks” as described in NHibernate reference (see Chapter 12): the adonet.batch_size and the StatelessSession. If you know how work the batcher, studying the code or watching the SQL log or reading this post, you can even change your code to improve performances having less round trips.

I haven’t used an “extreme” configuration (batch_size=500) but the result is:

To save 24 Companies, that mean 14424 entities, my code toke 39 roundtrips (in 5 transactions).

This result mean ~3050 entities per second, with normal behavior, and ~5300 entities per second using compiled queries (note the domain is something with parent-child relationship and a big NVARCHAR and not the same used by ORMBattle.NET).

If I play a little bit more, with the code, I may have even better performance.

Read All

Here I can show the code:

IList<NHCompany> result;
using (var session = Sf.OpenSession())
{
result = session.GetNamedQuery("NHCompany.All").List<NHCompany>();
}
foreach (NHCompany company in result)
{
writer.WriteLine(company);
foreach (NHEmployee employee in company.Employees)
{
writer.WriteLine(employee);
foreach (NHReport report in employee.Reports)
{
writer.WriteLine(report);
}
}
}

As you can see “read all” mean literally read-all and then show results in a log file. The difference here is that I’m loading 24 companies with all his employees and all reports (again 14424 entities) in only one roundtrip and only one SQL.

Read by ID

Again the code:

foreach (Company company in companies)
{
NHCompany foundCompany;
using (ISession session = Sf.OpenSession())
{
foundCompany = session.GetNamedQuery("NHCompany.One")
.SetInt32("pId", company.Id).UniqueResult<NHCompany>();
}

writer.WriteLine(foundCompany);
foreach (var foundEmployee in foundCompany.Employees)
{
writer.WriteLine(foundEmployee);
foreach (var foundReport in foundEmployee.Reports)
{
writer.WriteLine(foundReport);
}
}
}

Which sense has this test I don’t know, by the way it is loading again each company (24) with all his employees and all reports (again 14424 entities) but, in my implementation, in only 24 roundtrips.

Update

foreach (NHCompany company in companies)
{
company.Name += valueToAdd;
foreach (NHEmployee employee in company.Employees)
{
employee.Name += valueToAdd;
foreach (NHReport report in employee.Reports)
{
report.Text = valueToAdd + report.Text;
}
}
session.Update(company);
}

This code is updating each entity (again 14424) and I’m doing it in 5 transactions. Thanks to this test I found a missed feature in NHibernate (the code is there but the configuration does not allow its usage) because, so far, this code is working using 49 roundtrips per each company when we can obtain the same final result with 39 roundtrips in total (for all 14424). As you can see I’m using a normal ISession (you can see it because there is only a session.Update and StateLessSession does not work with cascade).

Even if NH2.1.0GA is performing this test in 49 roundtrips per each company, the final result is ~1550 updates per second, with normal behavior, and ~2450 updates per second using compiled queries.

Delete

public override void DeleteData()
{
using (var session = Sf.OpenStatelessSession())
using (var tx = session.BeginTransaction())
{
session.CreateQuery("delete from NHCompany").ExecuteUpdate();
tx.Commit();
}
}

Well… is there something to say here ?

It is an entirely database clean in only one SQL and only one roundtrip in only one transaction.

Conclusions

I’m sorry with Gergely because his fault was “only” to publish the wrong post in the wrong moment; as I said before, in other moment my reaction would be only close the browser.

Anyway my opinion about MDTD continuing being the same (MDTD = Monkey Driven Test Development).

30 April 2009

Empezando con NH: session

Posts anteriores: Empezando con NHibernate
Configuración

Cuando se empieza a trabajar con NH uno de los escollo es el manejo de sesiones; tal vez sea el más grande. La realidad es que hay muy poco que elegir y así muy poco que estudiar.

Los patrones de manejo de sesión son:

  • Open session in view (aka session-per-request)
    • Request, session y transaction tienen el mismo ciclo de vida
  • Session-per-Conversation (aka long-session)
    • Permanece abierta por más de un request
  • Conversation-per-Business Transaction (CpBT)
    • Permanece abierta por el tiempo que dura una transacción de negocio
  • Session-per-Call (anti pattern)
    • Permanece abierta por el tiempo que dure un query, o un save, o un update…
  • Session-per-application
    • Imposible usar en una aplicación real
    • Más que un pattern es una “Time bomb”

Sobre los último dos no vale la pena gastar ni una línea.

Con Session-per-Conversation (eschema disponible aquí) hay que tener cuidado porque no siempre funciona como uno se espera (léase abrir dos tabs en lugar que dos instancias de browser). Hay frameworks que facilitan el uso de session-per-request en mix con session-per-conversation y limitan la cantidad de conversations iniciadas a una. A mi gusto quedan sesión-per-request y conversation-per-business transaction (eschema disponible aquí).

Si pueden organizar la aplicación para usar session-per-request siempre, sería una buena solución. Si notan que los use-case, que necesitan una trasaction de negocio que involucra más de un request, son muchos, vayan pensando que session-per-request, en algún momento, le puede quedar corto. Si la aplicación es WinForm o WPF olvídense de session-per-request por el simple motivo que en esos ambientes no existe nada parecido a un request (ni siquiera el Call-context lo es).

Las recomendaciones

  • Recuerden que la session implementa UnitOfWork; la implementación del pattern UnitOfWork es la session de NHibernate.
  • Traten de mantener en la session lo que realmente se necesita que esté en la UnitOfWork; el Flush podría ser muy laaargo.
  • “Abracen” todas acciones de persistencia con una transaction, no importa que sean de lectura o escrictura.
  • Haganse la idea que la ISession no es la IDbConnection.
  • Haganse la idea que la ITransaction no es la IDbTransaction.
  • No encierren la ISession en una clase con Save, Update, FindBy etc., es completamente innecesario; en el DAO/Repository usen la ISession.
  • Si algo "no funciona" ante de pensar que sea un bug de NHibernate intenten escribir un test que reproduzca el error afuera de su aplicación (NH es muy usado, en el mundo, en varios entornos y en aplicaciones comerciales).
  • Antes de escribir su session-handler averigüen quien ya lo hizo; no intenten inventar, ya somos muchos los que han golpeado la cabeza, ustedes, en lo posible, evítenlo.
  • Asegúrense que su capa de acceso a datos (DAO o Repository) permita cambiar la estrategia de gestión de sesiones de persistencia; por ejemplo inyectando ISessionFactory a su DAO y usando GetCurrentSession(tambien se puede inyectar la ISession pero, en ese caso, asegúrense de conocer lo que pierden).
  • Eviten que sus DAO/Repository tengan referencia a un session-handler especifico (aunque suene similar no es lo mismo del punto anterior); en lo posible mantengan la implementación de DAO/Repository pegada solo y exclusivamente a NH.
  • Recuerden que el manejo de sesiones de persistencia es algo más cercano al manejo de cuestiones de infraestructura.
  • Al primer problema relacionado con lazy-loading asegúrense usar una estrategia de manejo de sesiones adecuada al caso de uso.
  • Si piensan necesitar un ISession.Evict preocúpense; es posible que el manejo de sesiones no sea el adecuado. Ni hablar si ven una aplicación con Evict por todos lados. El Evict es útil solo en algunos casos especiales.
  • Sepan que ISession no es solo Get, SaveOrUpdate, CreateQuery y CreateCriteria.
  • Investiguen porque parece que NH tiene dos métodos para hacer lo mismo; Get y Load no son lo mismo.
  • Aprendan a trabajar con entidades desconectadas (ISession.Lock, ISession.Merge)
  • Averigüen de qué se trata con IStatelessSession.

Donde encontrar session handlers

La primer fuente es NHibernate mismo. El name space NHibernate.Context contiene la clase WebSessionContext para manejo de sessiones en WEB y ThreadStaticSessionContext para manejo de sesiones en tests. Usando WebSessionContext no necesitan nada mas (a parte una implementación de IHttpModule) para manejar session-per-request y/o session-per-conversation en entorno WEB. Notar que las implementaciones disponibles en NHibernate se basan en el uso de GetCurrentSession y son descripats en NHibernate in Action.

Castle y Spring.NET ofrecen “semplificadores” de manejo de sessiones en WEB, WinForm y tests.

RhinoTools ofrece una implementación para WEB (session-per-request y/o session-per-conversation).

NHibernate.Burrow provee varias formas de manejo de sesiones orientado a WEB. Burrow tambien implementa algo muy similar a CpBT o mejor dicho implementa session-per-conversation sin limitaciones a una sola convesación por HttpSession.

uNhAddIns implementa todos los patterns. Como la implementación en NHibernate-Core tambien las implementaciones en uNhAddIns se basan en el uso de GetCurrentSession. Las implementaciones son disponibles en el namespace uNhAddIns.SessionEasier y uNhAddIns.Web.SessionEasier. La implementaciones de session-per-request y session-per-conversation ofrecen un uso “semplificado” respecto a las implementaciones en el core de NH ya que el Bind/Unbind es automatico (el Unbind automatico se activa solo si aceptan usar algún DynamicProxy, por ejemplo el mismo que usan en NH). Para lo que concierne la implementación de CpBT los invito a leer varios posts. Como ultima nota, sobre uNhAddIns, les aclaro que uNhAddIns no trae dependencias a algo mas que no sea NHibernate, todas las implementaciones de session-handlers pueden ser usadas a solas o con el IoC/AOP que prefieran.

27 April 2009

A Spring in NHibernate’s Conversation per Business Transaction

In my last post on CpBT (Conversation per Business Transaction) I have used Castle AOP. In uNhAddIns you can find examples, of CpBT usage, in WinForm, Castle.MonoRail and an introduction example for WCF (thanks to Gustavo Ringel and Alexander Surin).

The news is that now you can use the same code with Spring.AOP.

uNhAddIns.SpringAdapters

I’m not an expert with Spring and frankly was not so easy to find the better way to implements “all” classes needed. The mayor difficult was only the fact that Spring has a lot of very interesting features and the API is really fine-grained. You can obtain similar results in different ways. Erich Eichinger point me in various places of Spring's documentation before find all needed to completely reuse uNhAddIns.Adapters.Common.

Inheriting from AbstractConversationInterceptor the interceptor it self, the implementation for Spring and Castle, is not a big deal. My problem was only find the better way to wire the proxy factory to my interceptor; when I find it, between AutoProxyCreators, Advisor, Advise, custom ProxyFactory and so on, the result was very very simple:

public class ConversationalAttributeAutoProxyCreator : AbstractFilteringAutoProxyCreator
{
private readonly ReflectionConversationalMetaInfoStore store;

public ConversationalAttributeAutoProxyCreator(IConversationalMetaInfoStore store)
{
this.store = (ReflectionConversationalMetaInfoStore)store;
}

protected override bool IsEligibleForProxying(Type objType, string name)
{
if (store.GetMetadataFor(objType) == null)
{
return store.Add(objType);
}
return true;
}
}

As you can see… was trivial (Erich Eichinger said me: “no worries, once you get it, it is quite easy”).

The Spring configuration

Before look for “Spring programmatic configuration” I ask a link to Erich and he said :”you are just hitting our Achilles heel; programmatic conf. is not so nice ”.

In uNhAddIns.Adapters.CommonTests there are some common tests for CpBT AOP; there I’m using CommonServiceLocator and some abstract methods to configure the test for a specific IoC/AOP framework.

Well… this is the implementation using Spring’s programmatic configuration:

protected overrideIServiceLocator NewServiceLocator()
{
    IConfigurableApplicationContext context = newStaticApplicationContext();
    var objectFactory = context.ObjectFactory;
    objectFactory.RegisterInstance<ISpringConfigurationAccessor>(newTestSpringConfigurationAccessor(objectFactory));

    objectFactory.RegisterDefaultConversationAop();

    // Services for this test
   
var sl = newSpringServiceLocatorAdapter(objectFactory);

    objectFactory.RegisterInstance<IServiceLocator>(sl);

    objectFactory.Register<IConversationContainer, ThreadLocalConversationContainerStub>();

  objectFactory.Register<IConversationsContainerAccessor,ConversationsContainerAccessorStub>();

    objectFactory.Register<IDaoFactory, DaoFactoryStub>();

    objectFactory.Register<ISillyDao, SillyDaoStub>();

    return sl;
}

protected override voidRegisterAsTransient<TService, TImplementor>(IServiceLocator serviceLocator)
{
    var ca = serviceLocator.GetInstance<ISpringConfigurationAccessor>();
    ca.ObjectFactory.RegisterPrototype<TService, TImplementor>();
}

protected override voidRegisterInstanceForService<T>(IServiceLocator serviceLocator, T instance)
{
    var ca = serviceLocator.GetInstance<ISpringConfigurationAccessor>();
    ca.ObjectFactory.RegisterInstance(instance);
}

Really, I don’t understand why Erich said that the “programmatic conf. is not so nice”; I can’t see anything so nasty, do you ? ;)

kick it on DotNetKicks.com

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