I remember having to reference this “best practice” post when setting up a new project utilizing NHibernate. What a nightmare. Thankfully, there’s been some really positive activity on the Fluent NHibernate project, and configuration has become much more straightforward. In this post I am going to share my experience configuring NHibernate using:
Fluent NHibernate
Ninject
MySQL (Configuring any common database platform is trivial once you’ve seen it done)
To get my head around the basic configuration, I read the tutorial at the Fluent NHibernate site: http://fluentnhibernate.org/
After reading the tutorial, I had a good idea of the external dependencies I’d need to “inject” into my app.
Configuring the Repository
The primary point of entry for any data transferred to and from my database is via my repository. NHibernate’s ISession is what I will interface with to make queries, so I’m going to need that object created and injected into my repository.
Example of a simple repository:
public class Repository : IRepository
{
private ISession _session;
public Repository(ISession session)
{
_session = session;
}
public void Save<T>(T entity) where T : DomainEntity
{
}
public T Load<T>(int id) where T : DomainEntity
{
}
public IQueryable<T> Query<T>() where T : DomainEntity
{
}
public IQueryable<T> Query<T>(Expression<Func<T, bool>> where) where T : DomainEntity
{
}
}
The constructor of my class takes an instance of ISession. This is where the dependency will be injected into my Repository class.
Widdling down the “Best Practice” article
The most important part of an NHibernate configuration is your management of the SessionFactory and Session objects. The SessionFactory object is expensive to create, and should be made a Singleton. The ISession object should be retained for the lifecycle of the current request if you’re working on a web application. For a non-web project the lifecycle of the ISession should be kept around one per thread.
Many (if not all) of the major dependency injection frameworks offer this type of “lifecycle management” out of the box. Ninject is no exception; here is how I accomplished it:
internal class IoCConfiguration : StandardModule
{
public override void Load()
{
Bind<IRepository>().To<Repository>();
Bind<INHibernateSessionFactoryBuilder>().To<NHibernateSessionFactoryBuilder>().Using<SingletonBehavior>();
Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<INHibernateSessionFactoryBuilder>()
.GetSessionFactory()
.OpenSession())
.Using<OnePerRequestBehavior>();
}
}
Due to the expressive nature of the API, this code is really self-explanatory. Just for fun, compare this code with the mess from the NHibernate best practices article I mentioned eariler (http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx).
For completeness, here is the code to configure NHibnerate via Fluent Nhibernate for a MySql database:
public class NHibernateSessionFactoryBuilder : INHibernateSessionFactoryBuilder
{
private ISessionFactory _sessionFactory;
public ISessionFactory GetSessionFactory()
{
if(_sessionFactory == null)
{
_sessionFactory = CreateSessionFactory();
}
return _sessionFactory;
}
private ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(c => c.FromAppSetting("DBConnString")))
.Mappings(m => m.AutoMappings.Add(AutoPersistenceModel.MapEntitiesFromAssemblyOf<DomainClass>()
.Where(w => w.BaseType == typeof(DomainEntity))
.ConventionDiscovery.Add<PrimaryKeyConvention>()
.WithSetup(convention =>
{
convention.FindIdentity = t => t.Name == "Id";
convention.IsBaseType = type => type == typeof (DomainEntity);
}
)))
.BuildSessionFactory();
}
}
This is all best explained by the Fluent Nhibernate wiki (which is excellently written).
All this is a first swag, and I’d love to hear how it could be improved. Please leave a comment if you’ve got any questions or if you know of a way it can be better!