Fluent NHibernate mapping

This is an article which continues on a project that I started in a previous article about how to configure NHibernate using Fluent NHibernate. In this article we’ll use the Fluent NHibernate auto-mapping feature and test it using NUnit.
We’ll also let NHibernate generate the tables for us in our database so that we don’t have to think about it. The structure in our application will look like this:

Project overview

We’ve added two more entitites since the last project, FinancialRecord and RecordType, in Morkonomy.Core. We’ve also added a mapping test in our test project. The first change we’ll make is in our SessionFactoryBuilder:

    public static class SessionFactoryBuilder
    {
        public static ISessionFactory BuildSessionFactory()
        {
            return Fluently.Configure()
                .Database(SQLiteConfiguration
                            .Standard
                            .UsingFile("Morkonomy.db")
                            .ShowSql()
                )
                .Mappings(m =>
                    m.AutoMappings.Add(
                        AutoMap.AssemblyOf<Entity>()
                            .IgnoreBase<Entity>()
                        )
                    )
                .ExposeConfiguration(c =>
                {
                    new SchemaExport(c)
                        .Create(false, true);
                })
                .BuildSessionFactory();
        }
    }

Some parts has changed. We’ve added .ShowSql() so that we see the queries generated by NHibernate when we test our automapping. Also, we don’t want a table called Entity as it is our base table so we’ve told NHibernate to ingore it (.IgnoreBase()).
We add a schema export which will generate the tables in our database based on our entities. This will generate a new database structure everytime we use the SessionFactoryBuilder. If you don’t want to generate a new base every time (it can be annoying when you’re not testing but actually run the program) you can use the .Execute() method instead of the .Create() method and tell it only to make changes and update, not to purge and recreate.
It should be noted that Fluent NHibernate shouldn’t really be used with SQLite as there are some dialectal issues (as I’ve come to understand it). Fluent NHibernates SQLite dialect won’t work well with foreign keys as SQLite originally didn’t support foreign keys. It does now, but the Fluent NHibernate dialect hasn’t been completely updated, but you can choose whatever DB provider you want.

When we’ve changed our configuration we’ve solved the table building parts so that we don’t need to care any more about that. It is time to build, and test, our entities:

    /// <summary>
    /// A base class for all other entity classes
    /// </summary>
    public class Entity
    {
        public virtual int Id { get; set; }
    }
 
    /// <summary>
    /// A class to used to describe the type of a record
    /// </summary>
    public class RecordType : Entity
    {
        /// <summary>
        /// The name of the record type
        /// </summary>
        public virtual string Name { get; set; }
 
        /// <summary>
        /// A description of the type
        /// </summary>
        public virtual string Description { get; set; }
    }

This generates a RecordType entity with the properties Id, Name and Description. All you need to describe a record. For anyone that’s written C# code this is nothing strange. The only thing is that the properties to map must be virtual so that NHibernate can create proxy classes.

There is also our FinancialRecord class:

    /// <summary>
    /// A class representing debit/credit records
    /// </summary>
    public class FinancialRecord : Entity
    {
        /// <summary>
        /// The name of the financial debit/credit record
        /// </summary>
        public virtual string Name { get; set; }
 
        /// <summary>
        /// The value of the record
        /// </summary>
        public virtual double Value { get; set; }
 
        /// <summary>
        /// How often the record is due, byt month (1 = one month)
        /// </summary>
        public virtual int PeriodByMonth { get; set; }
 
        /// <summary>
        /// The kind of record we are dealing with
        /// </summary>
        public virtual RecordType RecordType { get; set; }
    }

What about the testing then? Well, it’s very simple. Create a class called MappingTest (according to the previous overview screenshot) and add the following code:

    [TestFixture]
    public class MappingTest
    {
        private ISession m_Session;
 
        [SetUp]
        public void _Setup()
        {
            m_Session = SessionFactoryBuilder.BuildSessionFactory().OpenSession();
        }
 
        [Test]
        public void FinancialRecordMappingTest()
        {
            RecordType recType = new RecordType() { Name = "two", Description = "Another description!?" };
 
            CustomEqualityComparer comparer = new CustomEqualityComparer();
            new PersistenceSpecification<FinancialRecord>(m_Session, comparer)
                .CheckProperty(p => p.Name, "Foo")
                .CheckProperty(p => p.PeriodByMonth, 3)
                .CheckProperty(p => p.Value, 5.99)
                .CheckReference(p => p.RecordType, recType)
                .VerifyTheMappings();
        }
 
        [Test]
        public void RecordTypeMappingTest()
        {
            new PersistenceSpecification<RecordType>(m_Session)
                .CheckProperty(p => p.Name, "Foo")
                .CheckProperty(p => p.Description, "Foo description!")
                .VerifyTheMappings();
        }
    }

As you can see we are using a class called CustomEqualistyComparer. We use this to tell NHibernate how to interpret the entities at the mapping stage. We don’t want it to compare the entities based on their memory allocation reference but rather on their ID’s, so it looks like this:

    public class CustomEqualityComparer : IEqualityComparer
    {
        public bool Equals(object x, object y)
        {
            if (x == null || y == null)
            {
                return false;
            }
 
            Entity xEntity = x as Entity;
            Entity yEntity = y as Entity;
 
            if (xEntity == null || yEntity == null)
            {
                return x.Equals(y);
            }
 
            return xEntity.Id == yEntity.Id;
        }
 
        public int GetHashCode(object obj)
        {
            Entity e = obj as Entity;
 
            if (e != null)
                return e.Id;
            else
                return base.GetHashCode();
        }
    }

If you run this test you should be able to read the following, hopefully, in the console:

------ Test started: Assembly: Morkonomy.Test.dll ------
 
NHibernate: INSERT INTO "Entity" DEFAULT VALUES; select last_insert_rowid()
NHibernate: INSERT INTO "RecordType" (Name, Description, Entity_id) VALUES (@p0, @p1, @p2);@p0 = 'two', @p1 = 'Another description!?', @p2 = 1
NHibernate: INSERT INTO "Entity" DEFAULT VALUES; select last_insert_rowid()
NHibernate: INSERT INTO "FinancialRecord" (Name, PeriodByMonth, Value, RecordType_id, Entity_id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 'Foo', @p1 = 3, @p2 = 5,99, @p3 = 1, @p4 = 2
NHibernate: SELECT financialr0_.Entity_id as Id0_0_, financialr0_.Name as Name1_0_, financialr0_.PeriodByMonth as PeriodBy3_1_0_, financialr0_.Value as Value1_0_, financialr0_.RecordType_id as RecordType5_1_0_ FROM "FinancialRecord" financialr0_ inner join "Entity" financialr0_1_ on financialr0_.Entity_id=financialr0_1_.Id WHERE financialr0_.Entity_id=@p0;@p0 = 2
 
NHibernate: INSERT INTO "Entity" DEFAULT VALUES; select last_insert_rowid()
NHibernate: INSERT INTO "RecordType" (Name, Description, Entity_id) VALUES (@p0, @p1, @p2);@p0 = 'Foo', @p1 = 'Foo description!', @p2 = 1
NHibernate: SELECT recordtype0_.Entity_id as Id3_0_, recordtype0_.Name as Name5_0_, recordtype0_.Description as Descript3_5_0_ FROM "RecordType" recordtype0_ inner join "Entity" recordtype0_1_ on recordtype0_.Entity_id=recordtype0_1_.Id WHERE recordtype0_.Entity_id=@p0;@p0 = 1
 
2 passed, 0 failed, 0 skipped, took 11,90 seconds (NUnit 2.5.7).

We’ll, then you are on your way with your first Fluent NHibernate auto mapping and testing!

A basic Fluent NHibernate configuration

I have some dealings with NHibernate (off and on) in my work and I thought I’d write about the basics for a NHibernate application. This example will use SQLite and Fluent nHibernate to make the mapping and database configuration easier.

We start with creating a project for our database managing, I call mine Morkonomy.Data (we make a home economics program). We add one more project that we call Morkonomy.Test which we’ll use to test our code. We will need NUnit to generate tests. The third project we need we’ll name Morkonomy.Core and will contain all the entities which we’ll map against. There is also a fourth, and for the time being, final project that we’ll call Morkonomy.Business, which will of course contain our business logic.

We’ll start by adding a folder in Morkonomy.Core which we’ll call ‘Entities’. In this folder we’ll create an Entity base class called simply Entity. It will only contain one property called Id as all our entities will have to have an Id column in the base:

    public class Entity
    {
        public virtual int Id { get; set; }
    }

In Morkonomy.Data we’ll need the references that comes with the fluent nhibernate package and a reference to System.Data.SQLite, so add those references and add them to the Morkonomy.Test project as well. In Morknomy.Data we’ll create a folder which we’ll call nHibernate in which we’ll add a class called SessionFactoryBuilder.cs. That class will, surprise surprise, build our ISessionFactory which we’ll need to create a NHibernate session.
Add the following code:

    public static class SessionFactoryBuilder
    {
        public static ISessionFactory BuildSessionFactory()
        {
            return Fluently.Configure()
                .Database(SQLiteConfiguration
                            .Standard
                            .UsingFile("Morkonomy.db")
                )
                .Mappings(m =>
                    m.AutoMappings.Add(
                        AutoMap.AssemblyOf<Entity>()
                        )
                    )
                .BuildSessionFactory();
 
        }
    }

In our test project we’ll add a folder we’ll call Data where all our data tests will reside. Create a class called ConnectionTest, we’ll use it to test our configuration against the database:

    [TestFixture]
    public class ConnectionTest
    {
        [Test]
        public void TestConnection()
        {
            ISessionFactory factory = SessionFactoryBuilder.BuildSessionFactory();
 
            Assert.That(factory, Is.Not.Null);
        }
    }

We should now have a structure similar to this:

A basic structure
A basic structure

If you run that test you will hopefully get the following error:

TestCase 'Morkonomy.Test.Data.ConnectionTest.TestConnection'
failed: FluentNHibernate.Cfg.FluentConfigurationException : An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
 
 
  ----> NHibernate.HibernateException : Could not create the driver from NHibernate.Driver.SQLite20Driver, NHibernate, Version=2.1.2.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4.
  ----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> NHibernate.HibernateException : The IDbCommand and IDbConnection implementation in the assembly System.Data.SQLite could not be found. Ensure that the assembly System.Data.SQLite is located in the application directory or in the Global Assembly Cache. If the assembly is in the GAC, use <qualifyAssembly/> element in the application configuration file to specify the full name of the assembly.
	d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs(98,0): at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
	NHibernate\SessionFactoryBuilder.cs(17,0): at Morkonomy.Data.NHibernate.SessionFactoryBuilder.BuildSessionFactory()
	Data\ConnectionTest.cs(17,0): at Morkonomy.Test.Data.ConnectionTest.TestConnection()
	--HibernateException
	at NHibernate.Connection.ConnectionProvider.ConfigureDriver(IDictionary`2 settings)
	at NHibernate.Connection.ConnectionProvider.Configure(IDictionary`2 settings)
	at NHibernate.Connection.ConnectionProviderFactory.NewConnectionProvider(IDictionary`2 settings)
	at NHibernate.Cfg.SettingsFactory.BuildSettings(IDictionary`2 properties)
	at NHibernate.Cfg.Configuration.BuildSettings()
	at NHibernate.Cfg.Configuration.BuildSessionFactory()
	d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs(93,0): at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
	--TargetInvocationException
	at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
	at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
	at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
	at System.Activator.CreateInstance(Type type, Boolean nonPublic)
	at NHibernate.Bytecode.ActivatorObjectsFactory.CreateInstance(Type type)
	at NHibernate.Connection.ConnectionProvider.ConfigureDriver(IDictionary`2 settings)
	--HibernateException
	at NHibernate.Driver.ReflectionBasedDriver..ctor(String driverAssemblyName, String connectionTypeName, String commandTypeName)
	at NHibernate.Driver.SQLite20Driver..ctor()

That means your reference to SQLite is incorrect. What you’ll have to do is select System.Data.SQLite in the Morkonomy.Test reference folder, go to properties and select:
Copy local: True

Do the same in Morkonomy.Data and after this it should work and you now have a working NHibernate configuration!

If you want more information about mapping? Read the next article about fluent mapping!