Blog

  • Home /
  • Blog /
  • What I Really, Really, Really Like About Using Fluent NHibernate

What I Really, Really, Really Like About Using Fluent NHibernate

March 8, 2009

Reusable Mappings

Something that slightly bothered me with the XML mappings of NHibernate, is the fact that some things need to be configured over and over again. Behold the following two mapping files:

Catalog:

<class name="Catalog" table="`Catalog`" optimistic-lock="version">
    <id name="Id" column="Id" type="Guid">
      <generator class="guid.comb" />
    </id>
    <version column="Version" name="Version" />
    <property name="Name" length="100" type="String">
      <column name="Name" />
    </property>

    ...

</class>

CatalogCategory:

<class name="CatalogCategory" table="`CatalogCategory`" optimistic-lock="version">
  <id name="Id" column="Id" type="Guid">
    <generator class="guid.comb" />
  </id>
  <version column="Version" name="Version" />
  <property name="Description" length="100" type="String">
    <column name="Description" />
  </property>

   ...

</class>

Suppose we have the luxury to choose how we deal with the database in our project. I do realize that's not always feasible because at some point in our careers, we've all seen what database masochism can do. Anyway, if would be making the shots, I would like to use a surrogate key for every table and I would recommend sequential GUIDs (called COMBs) for that. 

The mapping of the classes shown above both have the same configuration for the Id and Version properties. These properties typically live in a DomainEntity base class of some sort because we don't want to repeat that tedious code of putting those in every entity of our domain over and over again. It would be nice if we could somehow do the same for the NHibernate mapping files, which we can't (or at least, not that I know of).

Using Fluent NHibernate we can create an abstract mapping class for our DomainEntity from which we derive all entity mapping classes. The following code would give us the same result as the XML mapping files shown above:

DomainEntityMapping:

public abstract class DomainEntityMapping<TDomainEntity> 
	: ClassMap<TDomainEntity> where TDomainEntity : DomainEntity
{
    protected DomainEntityMapping()
    {
        Id(entity => entity.Id, "Id")
            .GeneratedBy.GuidComb();
        OptimisticLock.Version();
        Version(entity => entity.Version)
            .TheColumnNameIs("Version");
    }
}

CatalogMapping:

public class CatalogMapping : DomainEntityMapping<Catalog>
{
	public CatalogMapping()
	{
		Map(catalog=> catalog.Name, "Name");
	}
}

CatalogCategoryMapping:

public class CatalogCategoryMapping : DomainEntityMapping<CatalogCategory>
{
    public CatalogCategoryMapping()
    {
        Map(category=> category.Description, "Name");
    }
}

This way,  I can specify the mapping configuration for Id and Version in a single place which is really nice.

Mapping Tests

This is probably my most favorite feature of Fluent NHibernate. Given the fluent mapping configuration for the Category class shown earlier, the following test checks whether this mapping is valid or not:

[TestFixture]
public class When_verifying_the_class_mapping_of_a_catalog
    : NHibernateSpecification
{
	[Test]
	public void Then_a_catalog_object_should_be_persistable()
	{
		new PersistenceSpecification<Catalog>(Session)
		  .VerifyTheMappings();
	}
}

Running this test results in the following SQL statements being executed to an in-memory SQLite database:

NHibernate: INSERT INTO "Catalog" (Version, Name, Id) VALUES (@p0, @p1, @p2); @p0 = '1', @p1 = '', @p2 = 'c52126cb-f11e-47e4-a481-9bc600134d39'
NHibernate: SELECT catalog0_.Id as Id1_0_, catalog0_.Version as Version1_0_, catalog0_.Name as Name1_0_ FROM "Catalog" catalog0_ WHERE catalog0_.Id=@p0; @p0 = 'c52126cb-f11e-47e4-a481-9bc600134d39'

The following code shows the NHibernateSpecification base class for all my database tests. The code in this class deals with setting up the in-memory SQLite database and building the required schema based on the mappings. The Fluent NHibernate framework gives some really nice support for this as well:

[TestFixture]
public class NHibernateSpecification
    : Specification
{
    protected ISession Session { get; private set; }
    protected override void Establish_context()
    {
        var config = new SQLiteConfiguration()
            .InMemory()
            .ShowSql()
            .ToProperties();

        var sessionSource = new SessionSource(config,
            new RetailerPersistenceModel());

        Session = sessionSource.CreateSession();
        sessionSource.BuildSchema(Session);

        ProvideInitialData(Session);

        Session.Flush();
        Session.Clear();
   }

    protected override void Dispose_context()
    {
        if(null != Session)
        {
            Session.Dispose();
            Session = null;
        }
    }
}

Fluent NHibernate really lowers the barrier for configuring NHibernate, which is a really big thing in my book. I must admit that I was a bit sceptical at first, but now I noticed that I'm having a hard time going back to the standard XML mapping configuration of NHibernate itself. As Fluent NHibernate is still in an early development stage, some issues can come up. But my personal experience so far is that the user group is very responsive.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be