A fluent interface to NHibernate

Do you like NHibernate? Do you like XML? My answer would be yes for the former and no for the latter. But if you want to map your entities to the underlying database tables you have no other choice than use XML. Ok, you are right, we still have the possibility to use attributes for the mapping (e.g. by using Castle Active Record) but in this case we are "polluting" our nice domain objects with infrastructure related information which definitely does NOT belong into the domain model.

Here comes our salvation. We now have a third player in the field. As first published by Jeremy D. Miller and later on by others (James Gregory, Bobby Johnson, Zachariah Young, etc. ) we can map our domain objects by using a fluent interface which solves the following possible problems

  • Changing the property names of a domain model can break the NHibernate mapping
  • Changing the database fields can break the NHibernate mappings

and has the benefit of

  • we can write the mappings in plain old C#
  • the mapping is more expressive
  • the mapping is better testable

You can download the source code for the Fluent NHibernate project from here.

Sample

Let's make a quick sample. You can download it's source here.

In our domain model we have a Product class defined as follows

public class Product
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Decimal UnitPrice { get; set; }
    public virtual int UnitsOnStock { get; set; }
    public virtual bool Discontinued { get; set; }
}

This class we can now easily map to the underlying database with this code

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Map(x => x.UnitPrice);
        Map(x => x.UnitsOnStock);
        Map(x => x.Discontinued);
    }
 
}

Now let's write a quick test to see whether we can really e.g. add a new product to the underlying database. In our case the database used for tests is the SqlLite database.

Prerequisites

I have to write a helper class which will be my session source. The mapping framework already contains such a session source but its implementation does not fit my needs. Since it is not a complicate class I implement my own one. The session source class has to implement the interface ISessionSource also found in the mapping framework. Here is the code

public class MySessionSource : ISessionSource
{
    private readonly ISessionFactory _sessionFactory;
    private readonly Configuration _configuration;
 
    public MySessionSource(PersistenceModel model) : this(null, model)
    {
    }
 
    public MySessionSource(IDictionary<string, string> properties, PersistenceModel model)
    {
        if(model == null) throw new ArgumentException("Model cannot be null!");
 
        _configuration = new Configuration();
        if (properties == null)
            _configuration.Configure();
        else
            _configuration.AddProperties(properties);
 
        Model = model;
        model.Configure(_configuration);
 
        _sessionFactory = _configuration.BuildSessionFactory();
    }
 
    public PersistenceModel Model { get; private set; }
 
    public ISession CreateSession()
    {
        return _sessionFactory.OpenSession();
    }
 
    public void BuildSchema()
    {
        var session = CreateSession();
        BuildSchema(session);
    }
 
    public void BuildSchema(ISession session)
    {
        var connection = session.Connection;
 
        var drops = _configuration.GenerateDropSchemaScript(_sessionFactory.Dialect);
        executeScripts(drops, connection);
 
        var scripts = _configuration.GenerateSchemaCreationScript(_sessionFactory.Dialect);
        executeScripts(scripts, connection);
    }
 
    private static void executeScripts(string[] scripts, IDbConnection connection)
    {
        foreach (var script in scripts)
        {
            var command = connection.CreateCommand();
            command.CommandText = script;
            command.ExecuteNonQuery();
        }
    }
}

I have two overloaded constructors. I can either provide only the persistence model I use or pass the model and the necessary NHibernate configuration as dictionary of properties. In the former case the configuration is loaded from the usual hibernate.cfg.xml configuration file. The constructor then creates a new NHibernate configuration instance and uses the passed persistence model instance to feed the mapping information into the configuration instance.

The class also implements a method the create (or open) an new NHibernate session instance.

Finally we have a BuildSchema method which is overloaded. The second overload is needed when testing with SqlLite as database since when using this database in the in-memory mode (which we do in our unit tests) the database is destroyed whenever the session is closed. So, if I use a session instance to create the schema and then another for the test, then the latter does not have access to the database created by the former.

Base class for unit tests

I now write a base class for all unit test that I'll implement. This base class should be responsible for the (re-)creation of the database schema before each test runs. It should also open a new session object before each test which I can then use in my unit tests. Finally the base class should close an dispose the session after each test. Here is the code

public class FixtureBase
{
    private MySessionSource _source;
 
    protected ISession Session { get; private set; }
 
    [SetUp]
    public void SetupContext()
    {
        Before_each_test();
    }
 
    [TearDown]
    public void TearDownContext()
    {
        After_each_test();
    }
 
    protected virtual void Before_each_test()
    {
        _source = new MySessionSource(new TestModel());
        Session = _source.CreateSession();
        _source.BuildSchema(Session);
        CreateInitialData(Session);
        Session.Clear();
    }
 
    protected virtual void After_each_test()
    {
        Session.Close();
        Session.Dispose();
    }
 
    protected virtual void CreateInitialData(ISession session)
    {
    }
}

Note that the SetUp and TearDown methods just delegate to protected virtual methods Before_each_test and After_each_test respectively. The latter two methods can be overridden in any child class. In the Before_each_test method I use the session source class to a) create a new session instance and b) (re-)build the database schema. A call to the virtual method CreateInitialData is executed and then the session is cleared. The CreateInitialData method can be used in the child classes to setup the respective context for the unit tests.

The After_each_test method just closes and disposes the session.

The first unit test

Finally we can write our first test and verify whether the mapping with the fluent interface really works. First we want to try to add a new Product to the database. With all the prerequisites in place this is now easy. See the code below

[TestFixture]
public class Product_Fixture : FixtureBase
{
    [Test]
    public void Can_add_product_to_database()
    {
        var product = new Product
                          {
                              Name = "Apple",
                              UnitPrice = 0.25m,
                              UnitsOnStock = 1255,
                              Discontinued = false
                          };
        Session.Save(product);
 
        // Assertion
        Session.Flush();
        Session.Clear();
        var fromDb = Session.Get<Product>(product.Id);
        Assert.AreNotSame(product, fromDb);
        Assert.AreEqual(product.Name, fromDb.Name);
        Assert.AreEqual(product.UnitPrice, fromDb.UnitPrice);
        Assert.AreEqual(product.UnitsOnStock, fromDb.UnitsOnStock);
        Assert.AreEqual(product.Discontinued, fromDb.Discontinued);
    }
}
We define a new test class which inherits from our base class FixtureBase. The we define the test which creates a new instance of type Product and populates the various properties with sample data. We then call the Save method of the session and pass the product as a parameter.

Then we flush and clear the session and reload the Product from database. We assert that it has really been loaded from the database and not just taken out of NHibernate's first level cache (to avoid that we have flushed and cleared the session). Then we assert that the values of the properties all match.

Unit test revisited

If we have a lot of entities then we potentially have lot's of repetitive code to implement just to unit test all of our entities as above. Hey but wait a minute. There is a "better" way provided by the mapping framework. We can use the PersistenceSpecification class to eliminate the repetitive work. Let's look how our code will be

[Test]
public void Can_add_product_to_database_revisited()
{
    new PersistenceSpecification<Product>(SessionSource)
        .CheckProperty(x=>x.Name, "Apple")
        .CheckProperty(x=>x.UnitPrice, 0.25m)
        .CheckProperty(x=>x.UnitsOnStock, 2345)
        .CheckProperty(x=>x.Discontinued, true);
}

That's a nice reduction in lines of code. No "noise" any more, just the essential is left.

Note: Unfortunately this second approach has a side effect which in my opinion is not nice! The entity must inherit from the base class Entity provided by the mapping framework. This introduces a dependency in the domain model (the domain model must reference the mapping framework) and also is against the principle of POCO (plain old C# object). Maybe I want to provide a different entity base class. Well there is some room for improvement left...

Summary

If you want a clean domain model free from pollution by mapping attributes you had to define the mapping between entities and the underlying database with XML documents. XML is not very wrist friendly and also not very readable. Now there is a third alternative to define the mapping of entities to database - the fluent NHibernate API. One can now define the mapping in C# with a nice and very readable code.

As always you can download the code for the sample here.

Enjoy

Blog Signature Gabriel .

Print | posted on Monday, August 11, 2008 10:26 AM

Comments on this post

# re: A fluent interface to NHibernate

Requesting Gravatar...
<p>I like it :)</p>

<p>I started looking at the source code and as impressed (blog post)</p>

<p>As you know, I'm looking forward to the auto mappings feature when you get it ready (where they're inferred by convention rather than written by hand).</p>

<p>Will also be great to see an example application that uses your library. Perhaps that's a few iterations away, but at least your test cases are plentiful for those that want to see it in action :-)</p>
Left by Tobin Harris on Aug 12, 2008 12:16 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
Does this library support forigen keys? I mean sub tables?
Left by Charlie on Aug 13, 2008 4:38 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
@Charlie: yes, and keep an eye on my following posts where I analyze common mapping scenarios
Left by Gabriel Schenker on Aug 13, 2008 8:57 PM

# re: A fluent interface to NHibernate

Requesting Gravatar...
Verry slick. The convention over configuration I think will be the best approach. Grails uses it and it's really fun.

I've been searching lattely for different ORM's so I'll definitely be looking forward to your posts.

Thanks! You get a thumbs up from me :D
Left by Mihai on Aug 15, 2008 4:50 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
I don't like to do the NHibernate mappings either. Here is a tool I found that can generate NHibernate mappings.

http://www.kellermansoftware.com/p-30-nunit-test-generator.aspx


Left by Greg Finzer on Aug 22, 2008 3:04 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
I need to create a tool who can generate NHibernate mappings.No one like to do the NHibernate mappings either.
I found a tool like that u check that by this URL : Click here to Get generate NHibernate mappings Tool
Left by Praveen Prakash on Sep 19, 2008 2:02 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
Here is a tool which helps you to generate NHibernate mapping files as well as Entity classes.

http://www.mygenerationsoftware.com
Left by Muneer on Oct 23, 2008 1:48 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
Your demo app make no use of you custom "mySessionSource" class.
Left by pmlarocque on Nov 16, 2008 12:23 PM

# re: A fluent interface to NHibernate

Requesting Gravatar...
@pmlarocque: the Fluent NHibernate codebase has been updated and now my own implementation is not needed any more.
That's what happens when we are "living on the trunk"... ;-)
Left by nhibernate on Nov 17, 2008 12:49 AM

# re: A fluent interface to NHibernate

Requesting Gravatar...
Thanks... a LLLLOOOTTTTT....

I hate xml configs... I will read this later.. hopping I can do more elegant and easyfull relations...


thanks...
PS: If I found this very interessting I will put a link in my blog...
Left by Guilherme Morais on Dec 19, 2008 3:52 AM

Your comment:

 (will show your gravatar)
 
Please add 6 and 8 and type the answer here: