Logo

NHibernate

The object-relational mapper for .NET

A fluent interface to NHibernate - Part 1

Blog Signature Gabriel

This is the first of a series of articles on the topic. Other posts will follow

  • A fluent interface to NHibernate - Part 2 - Value Objects
  • A fluent interface to NHibernate - Part 3 - Mapping Relations
  • A fluent interface to NHibernate - Part 4 - Configuration
  • </ul>

    Introduction

    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
    • </ul>

      and has the benefit of

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

        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.

        Persistence Model

        I have to declare to the mapping framework where the mapping classes can be found. For this I define a persistence model class which inherits from the base class PersistenceModel.

        public class TestModel : PersistenceModel
        {
            public TestModel()
            {
                addMappingsFromAssembly(typeof(ProductMap).Assembly);
            }
        }

        In the constructor I define that all of my mapping classes can be found in the assembly which also contains the mapping class for the Product entity. If the mapping classes can be found in the current assembly I could also use the method addMappingsFromThisAssembly(). To just add a specific mapping I could use addMapping(new ProductMap()).

        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
        {
            protected SessionSource SessionSource { get; set; }
            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()
            {
                SessionSource = new SessionSource(new TestModel());
                Session = SessionSource.CreateSession();
                SessionSource.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.

        Before each test

        In the Before_each_test method I use the session source class to

        1. instantiate a new session source. I pass an instance of my persistence model to the constructor
        2. create a new session instance (the session instance is saved in an instance variable for further reference)
        3. (re-)build the database schema.
        4. A call to the virtual method CreateInitialData is executed. The CreateInitialData method can be used in the child classes to setup the respective context for the unit tests.
        5. the session is cleared.
        6. </ol>

          After each test

          The After_each_test method just closes and disposes the current session. In our case (we are using SqLite as database) this also means that the database (schema) is destroyed.

          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>(Session)
                  .CheckProperty(x=>x.Name, "Apple")
                  .CheckProperty(x=>x.UnitPrice, 0.25m)
                  .CheckProperty(x=>x.UnitsOnStock, 2345)
                  .CheckProperty(x=>x.Discontinued, true)
                  .VerifyTheMappings();
          }

          That's a nice reduction in lines of code. No "noise" any more, just the essential is 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 .


Posted Fri, 05 September 2008 09:07:46 AM by gabriel.schenker
Filed under: mapping

comments powered by Disqus
© NHibernate Community 2024