Friday, January 22, 2010 8:39 PM Sean Feldman

NHibernate Session Factory

Each time we use NHibernate, we have to share production and semi-production code for NHibernate SessionFactory. Production code is the portion that is actually responsible to generate the SessionFactory on startup. Semi-production code, is the code that generates SessionFactory for purpose of schema extraction (SQL statements we use to generate DB). This time around, the smell had to be removed. Having identical code duplicated not only risky, but also becomes intolerable once it grows beyond a single line. This is our new SessionBuilder, that leverages the same code to generate SessionFactory for run-time purpose and schema generation at “design” time.

private static ISessionFactory sessionFactory;
private ISession session;
 
public ISession GetSession()
{
  Initialize();
  if (session == null)
    session = sessionFactory.OpenSession();
 
  return session;
}
 
public void CloseSession()
{
  if (session.IsNull())
    return;
 
  session.Close();
  session.Dispose();
  session = null;
}
 
private static void Initialize()
{
  if (sessionFactory.IsNull())
    sessionFactory = GetProjectNHibernateConfiguraton().BuildSessionFactory();
}
 
private static FluentConfiguration GetProjectNHibernateConfiguraton()
{
  var nhibernateConfiguration = new Configuration().Configure();
 
  var model = AutoMap.AssemblyOf<Entity>().IgnoreBase<Entity>()
    .Where(type => typeof (Entity).IsAssignableFrom(type))
    .Conventions.AddFromAssemblyOf<Entity>()
    .UseOverridesFromAssemblyOf<Entity>();
 
  return Fluently.Configure(nhibernateConfiguration)
    .Mappings(mappingConfiguration => mappingConfiguration.AutoMappings.Add(model));
}
 
#region Manually used to generate DB schema SQL scripts
 

internal static string DROP_SCHEMA_SQL_SCRIPT_NAME =

new FileInfo(Path.Combine(Path.GetTempPath(), "Schema_Drop.sql")).FullName;

internal static string CREATE_SCHEMA_SQL_SCRIPT_NAME =

new FileInfo(Path.Combine(Path.GetTempPath(), "Schema_Create.sql")).FullName;

 
/// <summary>Use TestDriven.Net to run this method as a test to generate SQL scripts and their files.</summary>
internal static void Generate_Database_Schema_and_Create_SQL_script_files()
{
  GetProjectNHibernateConfiguraton()
    .ExposeConfiguration(SchemaGenerator)
    .BuildSessionFactory();
}
 
private static void SchemaGenerator(Configuration configuration)
{
  var schemaExport = new SchemaExport(configuration);
  schemaExport.SetOutputFile(DROP_SCHEMA_SQL_SCRIPT_NAME).Drop(true, false);
  schemaExport.SetOutputFile(CREATE_SCHEMA_SQL_SCRIPT_NAME).Create(true, false);
}
 
#endregion

Region represents the “design-time” code. And I was using Fluent NHibernate with auto-mapping to generate the entities.

Filed under:

Comments

# re: NHibernate Session Factory

Monday, January 18, 2010 1:31 AM by Michael Chandler

It seems like it would have been a better design to take in an Action<T> dependency (or you could interface it out if you really wanted to). ExposeConfiguration would then call on the dependency if it exists.

At the moment your SessionBuilder knows about how to create/drop your database, which isn't really its responsbility I don't think?

I also notice that you appear to have an IsNull() extension method which isn't used consistently (there are still checks for == null).

Sorry if I sound negative, just a bit of feedback :)

# re: NHibernate Session Factory

Monday, January 18, 2010 8:03 AM by Sean Feldman

@Michael,

No worries, on contrary, I appreciate your honest feedback. The null is in deed an extension I use, and sometime forget about it :)

In regards to responsibility, I thought about it. It looks like Session builder is not responsible to generate the SQL stuff, but does it make to create a static class to leverage SessionBuilder at the "design-time"? Not sure. Either way, I see what you mean. My choice was either to keep doing what we always did or try to make it better - this was a first step.