Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Wrapping up nHibernate

In a relative short span of time nHibernate has become a major member of my toolbox. It has become the way to work with a database, not only a small hap-snap apps but it’s also making big strides into a constantly evolving system I’m working on. Setting up nHibernate several times has given me the opportunity to do some playing around. Browsing around you can find several ways to do it, some ways just focus on getting it done, some ways focus on performance, and some ways focus on resource management. Here I would like to discuss my way where I tried to take all aspects in account. Don’t take it as the way; please do share your thoughts.

<update>After a very good comment by rui I have corrected some of the code for the repository part. Thanks ! Blogging is just the best public code review you can get :)</update>

Code will work with two very important nHibernate objects

  • The sessionfactory. This object swallows the configuration, from the mappings to the connectionstring to the database. Instantiating it is quite a job as it has to parse all mappings and check for corresponding domain classes. The good thing is that it will actively check all mappings; when the sessionfactory is successfully instantiated you know you’re more than halfway. (Note that the sessionfactory does not check the database, in case there are errors in columns names of the mappings or in the connectionstring your code will not hit an exception until it actually tries to connect to the database). The sessionfactory is thread-safe all your code can work with one and the same sessionfactory. And as it is expensive to create the thing it pays off to create it only once.
  • The session. The sessionfactory provides you with session objects to work with the database. A session wraps up an actual connection to the database, so it holds an expensive unmanged resource. The mantra for "classical" ado.net code was always to open the connection as late as possible and to close immediately after firing your sql. More details on that here. The nHibernate sessionfactory provides session objects containing an open connection to the database. The session object has a method to close the connection, but there are several reasons not to do that. The most obvious one is lazy loading. For example when you load an invoice object from the database nHibernate will not load the data of the associated customer until your code actively touches the customer’s properties. In case your code doesn’t touch the customer the data will not be loaded. To load the data from the database nHibernate needs an open connection. In case you had already closed the session your code will hit a LazyLoadException. So a session object holds an open connection to the database, which requires extra care.

I’m going to manage both the sessionfactory and the session in one nHibernateHelper class. The code needs only one sessionfactory, which has to be instantiated once. The sessionfactory is going to be a static (shared) member of the class. I took the idea to instantiate the sessionfactory in a static constructor from an nice article on theserverside. A static constructor fires the moment the class is loaded. That is the moment the class is first touched by running code. In the original code the configuration is loaded from a configuration file. My problem with that is that I want to be independent from that for reasons of testability and custom configuration. Most settings can be hard coded but something like the database connectionstring has to be set from code. A static constructor does not have any parameters and I can not set any members, the moment I touch the class the static constructor fires first and I’m too late. What does work is a small helper class.

internal class nHibernateConnectionHelper

{

    internal static string connectionString = "";

}

  

internal class NhibernateHelper : INhibernateHelper

{

    private static readonly ISessionFactory sessionFactory;

  

    static NhibernateHelper()

    {

        Configuration cfg = new Configuration();

        IDictionary props = new Hashtable();

        props.Add("hibernate.dialect", "NHibernate.Dialect.MsSql2005Dialect");

        props.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");

        props.Add("hibernate.connection.connection_string", nHibernateConnectionHelper.connectionString);

        cfg.SetProperties(props);

        cfg.AddAssembly("dlcr.domain");

        sessionFactory = cfg.BuildSessionFactory();

    }

 

When the nHibernateConnectionHelperClass is touched first the static constructor of the NhibernateHelper class reads the updated connectionstring. It is used like this:

public class NhibernateHelperFactory

{

    public static INhibernateHelper CreateHelper(string dbConnection)

    {

        nHibernateConnectionHelper.connectionString = dbConnection;

        return new NhibernateHelper();

    }

}

 

Now the static constructor works as intended. This trick also works when both classes are in the same cs file. How the sessionfactory itself is set up is in a previous post.

With the sessionfactory ready the nHibernatehelper can start its core business: managing a session. A new session is instantiated and opened in the instance constructor. This constructor performs some checks whether the sessionfactory will provide a session with the expected database. It reads the connectionstring from the sessionfactory property as described in the previous post.

internal NhibernateHelper()

{

    if (string.IsNullOrEmpty(nHibernateConnectionHelper.connectionString))

        throw new Exception("Sessionfactory needs a connectionstring");

    if (nHibernateConnectionHelper.connectionString != connectionString)

        throw new Exception(string.Format("Sessionfactory connection allready initialized as {0}",connectionString));

    currentSession = sessionFactory.OpenSession();

}

 

As my nHibernateHelper objects wrap up an unmanaged resource (the database connection in the currentSession object) it has to implement IDisposable. The session object itself also implements IDisposable so the helper’s implementation can be pretty straightforward.

public void Dispose()

{

    currentSession.Dispose();

}

 

The only thing exposed is the nHibernateHelperFactory which servers IHibernateHelper objects. My IHibernateHelper is pretty straightforward

public interface INhibernateHelper : IDisposable

{

    IQuery Query(string className);

    IQuery Query(string className, string propertyName, string propertyValue);

    IQuery Query(string className, string propertyName, long propertyValue);

    IQuery Query(string className, string whereClause);

    void Save(object domainObject);

    void Save(object[] domainObjects);

    void Delete(object domainObject);

}

 

It has methods to query, save or delete objects. These are the methods my repository needs to interact with the database. This is a sample repository

public class Repository

{

    private readonly INhibernateHelper nhh;

  

    public Repository(INhibernateHelper nHhibernateHelper)

    {

        nhh = nHhibernateHelper;

    }

  

    public IList<IBoeking> Boekingen()

    {

        return nhh.Query("Boeking").List<IBoeking>();

    }

  

    public IBTWpercentage BTWpercentage(string naam)

    {

        IQuery query = nhh.Query("BTWpercentage", "Omschrijving", naam);

        return query.UniqueResult<IBTWpercentage>();

    }

  

    public void Save(object o)

    {

        nhh.Save(o);

    }

  

}

 

The helper is injected in the repository’s constructor. For testing purposes I could also inject a mock.

The overall result is that by using a disposable helper I’m in full control of the connection to the database and I have all nHibernate’s benefits like lazy loading.

[Test]

public void CanDemoHibernate()

{

  

    using (INhibernateHelper nhl = NhibernateHelperFactory.CreateHelper("Data Source=.;Initial Catalog=DLCR;Integrated Security=True"))

    {

        Repository rps = new Repository(nhl)

        IBoeking bks = StubFactory.BoekingStub();

        IBTWpercentage bts = StubFactory.BTWstub();

  

        Boeking bk = new Boeking();

        bk.Omschrijving = bks.Omschrijving;

        bk.Totaal = bks.Totaal;

        bk.BTW = bts.Percentage;

        rps.Save(bk);

  

        // Lazy load ahead

        ISet<BoekingsRegel> regels = bk.Regels;

        foreach (BoekingsRegel regel in regels)

        {

            Console.Write(regel.DeDato);

            tab();

            Console.Write(regel.Links);

            tab();

            Console.WriteLine(regel.Rechts);

        }

        Assert.Greater(regels.Count, 0);

    }

}

 

By using the helper I will be sure the session is always properly closed, also when an exception is hit.

Perhaps I’m somewhat over concerned when it comes to keeping control over open connections. Once I doubted ado.net’s connection pooling only to find out that works very well. Also nHibernate does a good job of keeping the number of open connection’s under control. When I open multiple repositories each using it’s own nHibernateHelper object these will all use the same connection. My main point is that my helper gives me the feeling I’m still in control without sacrificing performance or functionality.

This entry was posted in Coding, Data, Featured. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/pvanooijen/default.aspx pvanooijen

    Creating the sessionfactory is expensive. Opening a session is not. Compare it to Connection.Open in ADO.NET

  • David

    I’m new to nHibernate and I’m wondering about the performance cost of creating a new session using OpenSession() especially when a complex asp.net page could ask the Repository 10’s of times. Or am I going about it wrong?

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    @Ben,

    Session close does do more than just clossing the connection. Perhaps it does not even close the actuel connection. You can also work with a long running session in nHibernate to which your code connects and disconnects. I’m not doing that here. Performing a session close here will lead to lazy load exceptions.

    You’re quite right about the repositories. This here is to much of a hap snap thing pointing at a direction to continue. As promised, I’ll elaborate on that later.

    In most asp.net examples it’s common practice to store the session in the httpcontext. But most of the samples don’t pay much attention to the sessionfactory. Be my guest and store this helperobject in the session.

    2.0 ? That crept in quietely :)

  • http://www.flux88.com Ben Scheirman

    a couple of things to note:

    * session.close != connection.close

    Closing the session doesn’t necessarily prevent you from lazy loading. The session just has to be around, because it carries with it an identity map and some other internal state required for lazy loading to work. Re-opening the connection is not an issue. Just don’t dispose the session.

    * your repository should line up with domain entities

    If you have a customer, you’d have CustomerRepository. If customer had addresses (value objects), then you’d retrieve them through the customer object itself (or via query on Customer service, depending on your preference) but there wouldn’t be an AddressRepository. DDD by Evans can shed some light on this. There shouldn’t be one repository for all entities. RhinoCommons has a good implementation of IRepository where T is your entity.

    * if you’re looking at using this in ASP.NET, it is a good idea to scope your session in an HttpModule, so you can open it at the begin request and close at the end. This offers a clean lifecycle. Shorter ones can prevent you from benefitting from cache & lazy loading, and longer ones can stay around WAY too long hogging limited resources. Take a look at SessionScope, also in RhinoCommons.

    Also, you might be interested in updating your sample to 2.0, which was just released :)

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    @Rui : you’re absolutely right! Thanks for setting that straight. I’ve corrected the post itself

    @cristian : I will dive deeper into that in a later post. Which will also look at the actual implementaion of the other helper methods.

  • Rui Santos

    … “it isn’t created by Repository therefore shouldn’t be disposed by it”.

    Why? I would like to do something like this.

    INhibernateHelper nhl = NhibernateHelperFactory.CreateHelper(“…”);

    Repository rep1 = new Repository(nhl);
    Repository rep2 = new Repository(nhl);

    Who disposes INhibernateHelper? rep1 or rep2.

    maybe …

    using(INhibernateHelper nhl = NhibernateHelperFactory.CreateHelper(“…”))
    {
    Repository rep1 = new Repository(nhl);
    // do stuff with rep1
    Repository rep2 = new Repository(nhl);
    // do stuff with rep2

    nhl.Commit();
    }

    cheers,
    rui

  • Rui Santos

    It seems to me that the INhibernateHelper shouldn’t be disposed by Repository. It an injected dependency, it isn’t created be Repository therefore shouldn’t be disposed be it.

    Cheers,
    Rui

  • cristian

    Nice pattern! Throw in some generics and it’s even better.