C# – Ensure NHibernate SessionFactory is only created once

cfluent-nhibernatenhibernatesessionfactory

I have written an NHibernateSessionFactory class which holds a static Nhibernate ISessionFactory. This is used to make sure we only have one session factory, and the first time OpenSession() is called I create the actuall SessionFactory – next times I use the same and open a session on it. The code looks like this:

public class NhibernateSessionFactory : INhibernateSessionFactory
{
    private static ISessionFactory _sessionFactory;

    public ISession OpenSession()
    {
        if (_sessionFactory == null)
        {
            var cfg = Fluently.Configure().
                Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
                Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
            _sessionFactory = cfg.BuildSessionFactory();
            BuildSchema(cfg);
        }
        return _sessionFactory.OpenSession();
    }

    private static void BuildSchema(FluentConfiguration configuration)
    {
        var sessionSource = new SessionSource(configuration);
        var session = sessionSource.CreateSession();
        sessionSource.BuildSchema(session);            
    }
}

Now I have a problem. My application is split between client and server. The Nhibernate stuff is on the server side. On startup both my client and server wants to access the database through some services which will use the NhibernateSessionFactory. Result is a race condition to whether the _sessionFactory is created before the request comes from the client. If it isn't it will fail..

I guess I need some sort of queueing or wait mechanism in the NhibernateSessionFactory, but I'm not sure about what to do. Anyone had the same problem before? What's the best solution?

Best Answer

The sessionFactory must be a thread-safe singleton.

A common pattern in Java is to build the sessionFactory in a static initializer. See HibernateUtil. You can do the same in C#.

There are other patterns to implement singleton, including the usage of lock or synchronized sections. Here is slight variant that should solve your problem if I understood it correctly.

static readonly object factorylock = new object();

public ISession OpenSession()
{
    lock (factorylock)
    {
       if (_sessionFactory == null)
       {
            var cfg = Fluently.Configure().
               Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
               Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
            _sessionFactory = cfg.BuildSessionFactory();
            BuildSchema(cfg);
        }
    }
    return _sessionFactory.OpenSession();
}
Related Topic