Published: 16 Apr 2009
By: Gabriel Schenker
Download Sample Code

In this second part Gabriel Schenker continues his overview of the NHibernate OR/M.

Contents [hide]

Introduction

In the first part [1] of this article series I have introduced NHibernate and its sister project Fluent NHibernate. I have discussed the perquisites needed to start developing a NHibernate based application. Finally I have introduced a simple domain model which I then took as a base to implement. The first entity of this domain was then implemented and mapped. The unit test for the mapping was discussed.

In this second part I’ll continue to implement and map the remaining part of the domain.

Your very first NHibernate application series

  • Part 1 In this series of articles Gabriel Schenker want to show and discuss which pieces are needed to successfully write an application based on NHibernate and Fluent NHibernate.
  • Part 2 In this second part Gabriel Schenker continues his overview of the NHibernate OR/M.
  • Part 3 In this part of the series about NHibernate and its sister product Fluent NHibernate, Gabriel Schenker introduces the auto mapping feature of Fluent NHibernate.
  • Implementing and mapping the remaining domain objects

    First let’s implement and map the Product class. This process is similar to the one used when defining and mapping the customer object. Let’s first have a look at the implementation of the product class

    To keep our sample simple I have only implemented the most important properties. The mapping is straight forward and very similar to the mapping of the customer class in the first part of this article. So I don’t want to discuss the details again. Below you can see the implementation of the ProductMapping class

    Again the unit test for the mapping is similar to the unit test of the customer mapping class. We can use the PersistenceSpecification helper class of the Fluent NHibernate framework to facilitate this task.

    The PersistenceSpecification class offers a fluent interface to define the exact testing context. The mapping of an individual property can be tested with the aid of the CheckProperty method which expects as a first parameter a lambda expression of the property to map and as a second parameter a value which is assigned to the property during the test.

    Certainly you might want to know what exactly is happing during the test. The easiest way to do this is to enable the logging of the SQL produced by NHibernate. This is very easy - we just have to change the configuration in the base fixture class as follows

    The only thing we have changed is the .ShowSql() method call we have added in the SetupContext method of our FixtureBase class. When running the above unit test the following output is generated by NHibernate

    Figure 1: Unit Test Session window of Resharper when running the product mapping unit test

    Unit Test Session window of Resharper when running the product mapping unit test

    As we can see the unit test creates an insert statement with the values provided and subsequently reloads the data written to the database with a select statement.

    Now we come to a more interesting piece of the domain, the order and its order items. Let’s start with the OrderItem class. Here is its definition

    Again for simplicity only the most important properties are implemented. Adding additional properties is straight forward and is left for the reader as an exercise. Below the mapping for this class is shown. Please note the new keyword References. With this keyword we define a many-to-one relation between an order item and a product. That is each order item has/references exactly one product whilst every product can be referenced by many order items (in different orders!). With the .Not.Nullable() statement we declare that the reference to a product is mandatory (otherwise an order item is in an invalid state).

    Note as well that the Id of the order item class is not mapped as a key. An order item is not an entity but rather a value object [2]. It cannot exist on its own. An instance of an order item can only be defined in the context of an order. As such the Id of the order item is only an internally used index to provide a sort index for order items of an order. The Id of an order item has to be defined by the order object when a new order item is added to it.

    The unit test for the mapping is shown below

    Note how the reference to the product is checked with the CheckReference method. There is one problem though with this test. It fails. This is due to the fact that we have not defined when two instances of type product are the same. We thus have to override the Equals and the GetHashCode methods inherited from the Object base class. This can be done as shown below

    An even better way would be to define an entity base class which implements these two methods. All domain entities would then inherit from this base class. You can find a detailed discussion about identity, equality and hash code in this [3] article.

    Let’s define such a (generic) base class now from which all entities will then inherit

    Now the product (as well as the customer, employee and order) class has to inherit from this base class as follows

    Once we have defined equality for the product we can now re-execute the unit test and it will pass this time. When running the unit test the following output is produced

    Figure 2: Result of the unit test verifying the mapping of the order item class

    Result of the unit test verifying the mapping of the order item class

    Note how Fluent NHibernate automatically inserts the product for us which is then referenced by the order item object.

    The final piece is the implementation and mapping of the order class. The definition of the order class is given below

    Note that it is very important not to expose the OrderItems collection as List<T> but rather as IList<T> (or even as IEnumerable<T>). Otherwise you will get a type cast exception.

    The mapping of the order class can be seen here

    Again we have two References elements in the mapping. An order has a many-to-one relation to a customer as well as to an employee (who records the order).

    The new and interesting part here is the HasMany element. With it we can define a one-to-many relation. The order object contains a list of order items. The collection of order items belonging to an order are returned as a list. The index of the list is mapped to a column called ListIndex of the corresponding table in the database. The type of this column in the table is int. We could as well map the order items as a set or other (interesting) collection type.

    The unit test which verifies the mapping is presented below

    The above test is a bit lengthy since we have a lot of setup. We need products to be able to define meaningful order items. These products we have to explicitly save to the database. This is done with the aid of the session object. Now we can define order items which reference these products. We also need a customer and an employee object. Having defined all these elements we can now verify or test the mapping of the order entity.

    Please note especially the .CheckList(…) method that is used to verify the mapping of the order items list.

    Summary

    In part 2 of the article series on NHibernate and Fluent NHibernate I have continued to implement the remaining part of the domain. I have discussed the mapping of various forms of relations between different entities. For all mappings I have presented the code needed to verify the mappings.

    In my next article I’ll show you how further refactor and improve the mapping of our domain model. I’ll then discuss the usage of conventions and finally show how we can use the auto-mapping capabilities of Fluent NHibernate to completely avoid the explicit mapping of entities. Stay tuned.

    References

    Appendix

    Installing Ruby to build Fluent NHibernate

    To be able to compile the Fluent NHibernate project you need to install Ruby [4] on your system since Rake [5] is used as a build engine. Ruby is open source and thus free. The installation is quick and painless. It doesn’t take a lot of space on your hard disk neither. Ruby is very popular and powerful for things like writing build scripts. At the time of this writing version 1.9.1 is the official and recommended one.

    Once you have installed Ruby you need some extra libraries for it. These additional libraries are called Ruby Gems and can be downloaded from the internet as well. In our case we don’t have to do it manually. The authors of Fluent NHibernate have prepared a batch file which automates this task for us. So please navigate to the root directory of Fluent NHibernate and locate the file InstallGems.bat. Double click this file and the necessary Gems will be downloaded from the internet and installed. When the Gems are installed (this can take several minutes, so please be patient) we are ready for our last step. Still in the root directory of Fluent NHibernate double click on the file build.bat. The project is compiled and all the unit tests are executed. If the build (including the tests) was successful you should find all artifacts (assemblies and the like) in the sub-folder build.

    Downloading NHibernate

    If you want to also download NHibernate then just create another directory on your file system, e.g. c:\dev\NHibernate. Right click on this directory and choose the context menu item Checkout. Enter the following URL and click OK.

    https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk

    Now the complete source code is downloaded. This will take some time depending on the speed of your network connection. Once everything is downloaded you can build the project. Just follow the instructions in the file readme.txt in the nhibernate sub-folder.

    <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Gabriel Schenker

    Gabriel Schenker is a independent consultant, trainer, mentor and developer. He lives in Switzerland near to Zurich. His special focus is on practicing lean or friction-less software development. This includes practicing TDD, BDD and DDD. He is constantly advocating, promoting and supporting a cont...

    This author has published 4 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    A Feature-driven Comparison of Entity Framework and NHibernate-2nd Level Caching
    Where would you place caching in your layered solution? Two main patterns exist for caching in appli...
    A Feature-driven Comparison of Entity Framework and NHibernate - Queries
    Let's explore what Entity Framework and NHibernate has to offer when it comes to their query capabil...
    A Feature-driven Comparison of Entity Framework and NHibernate—Fetch Plans
    This article is about fetch plans-a recognized and common way for developers to instruct the O/RM ab...
    A Feature-driven Comparison of Entity Framework and NHibernate - Self-tracking entities
    In this article, Dino Esposito introduces self-tracking entities.
    .NET type generation for NHibernate mapping collections
    An overview of .NET type generation for NHibernate mapping collections.

    You might also be interested in the following related blog posts


    Oredev Wrap-Up read more
    Introducing SharePoint 2010 Training at U2U read more
    Silverlight From Zero read more
    WPF 4 (VS 2010 and .NET 4.0 Series) read more
    A new approach to build iGoogle/Facebook like sites with Asp.Net: Kalitte Widget Toolkit read more
    Building A Product For Real read more
    My History of Visual Studio (Part 8) read more
    Microsoft announced the beta release of IIS Application Warm-Up read more
    My History of Visual Studio (Part 6) read more
    URL Routing with ASP.NET 4 Web Forms (VS 2010 and .NET 4.0 Series) read more
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder GeneratedBy.Assigned() for OrderItem Noam Gal 5/22/2009 8:38 AM
    RE: GeneratedBy.Assigned() for OrderItem Gabriel Schenker 5/22/2009 10:53 AM
    placeholder Terrible Dustin Davis 5/29/2009 7:57 PM
    RE: Terrible Gabriel Schenker 5/30/2009 2:21 PM
    placeholder RE: RE: Terrible Dustin Davis 5/31/2009 2:47 AM
    Tests Fail Chris Breisch 9/2/2009 10:43 AM
    placeholder Very Nice Job Luis Blanco 10/10/2009 11:08 AM
    corrections to make Yuksel Daskin 2/8/2010 10:56 AM
    placeholder Test throws errors Na Ko 3/19/2010 9:11 PM
    Some questions? Bengt Berge 4/17/2009 6:44 AM
    placeholder RE: Some questions? Gabriel Schenker 4/17/2009 8:44 AM

    Please login to rate or to leave a comment.