Fluent NHibernate Session Magic

Summary

If you’ve spent any time with NHibernate or Fluent NHibernate, you’ll know how annoying it is to use the .Query() method in every LINQ query. It’s especially a problem for situations where you must convert Entity Framework or LINQ-to-SQL to NHibernate, since you have to convert every LINQ query in your code. In this blog post, I’m going to show how to get rid of this construct. In the future I’ll add this to the NHibernate mapping generator to allow this syntax to be used any time you auto-generate your table mappings.

NHibernate.ISession

I’m going to mention up-front that I was not the brains behind this discovery.  My colleague Samer Adra (Blog, Linked-In, Twitter, Stack Overflow) played around with this code to get it to work.  So I’m going to blog about it so everybody can start using this technique and get rid of the annoying .Query<Tablename>() syntax.

The first thing that needs to be changed is the ISession interface.  To do that, you need to default all the methods and properties that are used by the ISession object.  It starts like this:

public class SessionWrapper : ISession
{
  private readonly ISession innerSession;
  public SessionWrapper(ISession innerSession)
  {
    this.innerSession = innerSession;
  }
  public void Dispose()
  {
    innerSession.Dispose();
  }
  ... more
}

And it goes on and on (download the sample code).

I setup the project with two tables in it.  These table mappings connect to tables in MS SQL Server.  If you’ve followed this blog you know how to get the mappings, if not, then you’ll need to download the NHibernate Mapping Generator from my GitHub account and generate the mappings automatically.  Then you can go into the data project and find the table mapping cs file and copy the code.  You can get the mapping generator here.

Anyway, I added these two lines of code to the bottom of the SessionWrapper object shown above:

// Table mappings follow
public IQueryable<DataLayer.Department> Department
{
  get { return innerSession.Query<DataLayer.Department>(); }
}
public IQueryable<DataLayer.Store> Store
{
  get { return innerSession.Query<DataLayer.Store>(); }
}

Next, I had to modify the context to handle the session wrapper.  That only required me to change the OpenSession method:

public static SessionWrapper OpenSession()
{
  return new SessionWrapper(SessionFactory.OpenSession());
}

Now for the final code inside the Program.cs file:

using (var db = MSSQLSessionFactory.OpenSession())
{
  var query = (from d in db.Department select d).ToList();
  foreach (var item in query)
  {
    Console.WriteLine(item.name);
  }
  Console.ReadKey();
}

That’s it. Obviously, creating a method for each table inside the SessionWrapper is the most tedious aspect of this process. That’s why I’m going to add it to the NHibernate table generator project and generate this session automatically. Also, you’ll need to support the stateless session (IStatelessSession) if you intend to use stateless sessions in your projects. The same code will need to go into a stateless session wrapper as well.

Cross Database Support

One other thing to note is that the database that this table is located in is the sampledata database. If there was a Department table in another database and we wanted to be able to access both tables in one query, then we’ll need a unique name inside the SessionWrapper object. One solution is to create a naming convention that uses the database name with the table name. I may use a scheme for that in the mapping generator or I might leave it to the end user to come up with a scheme of their own. Just be aware of that possible issue.

Download the Code

You can download the code at my GitHub account here.  Don’t forget to go into the MSSQLSessionFactory.cs file and change the server instance (search for “YOURSERVERINSTANCE”).

Leave a Reply