Friday, April 17, 2009

Fluent NHibernate and Linq to NHibernate Demo Project

Introduction

This is my so long waited demo project showcasing the use of Fluent NHibernate and Linq to NHibernate (and some other interesting bits).

First of all, I you are completely new to NHibernate I encourage you to take a look at my previous introductory article here.

Disclaimer

Before commencing, I want to make a disclaimer about this project, as you may expect, this is just demo code, not intended to be take too serious, please use it just a *soft* guide of how very basic things can be done using NHibernate. However, I’ve tried to make my best implementing the code for this article, with time limitations and all the related issues that an active developer have.

Prerequisites

.Net Framework 3.5 SP1

Visual Studio 2008

To run the test from inside Visual Studio : TestDriven.Net

MSSQL Server 2005 with the AdventureWorks database installed.

All other dependencies (assemblies) are included within the solution.

Lets go

What is this about? Take a look at the solution structure:

Solution-1


I’m going to explain what’s the purpose of each of those projects:

NHibernateSample.Model:

This is the simplest one, here I’ve created the classes that are going to be mapped against our database, those are just POCO classes that represent a view of the real database. Take a look at this image:

ModelDiagram 

Each class must overrides its GetHashCode method (which should be implement in a way that that returns unique results for each unique entity)  and its Equals method in order to allow to NHibernate to handle the loading and session caching process of entities. Those methods look similar in almost all the cases, except when we are handling entities that have composite ids.
Lets take a look at how this is being done in the AddressType class that has its AddressTypeID property as primary key:

        public override int GetHashCode()

        {

            return HashCodeGenerator.GenerateHashCode(AddressTypeID);

        }

        public override bool Equals(object obj)

        {

            return this.IsEqual(obj);

        }

The GenerateHashCode method from the HashCodeGenerator class (NHibernateSample.Model/Helper/HashCodeGenerator.cs) and it looks like:

    public static class HashCodeGenerator

    {

        public static int GenerateHashCode(params object[] keys)

        {

            int hash = 17;

 

            foreach (var item in keys)

            {

                int itemHashCode;

                if (item == null)

                {

                    itemHashCode = 1;

                }

                else

                {

                    itemHashCode = item.GetHashCode();

                }

                hash = hash * 23 + itemHashCode;

            }

 

            return hash;

        }

    }

As you can see, nothing glamorous, I’m just assuring that the result of the method is unique.

The override of the Equals method is using the IsEqual extension method from the EqualityHelper class (NHibernateSample.Model/Helper/EqualityHelper.cs) and it looks like:

    public static class EqualityHelper

    {

        public static bool IsEqual<T>(this T source, object obj) where T : class

        {

            var target = obj as T;

            if (obj == null)

            {

                return false;

            }

            return target.GetHashCode().Equals(source.GetHashCode());

        }

    }

As you can see, it only checks the equality of the method GetHashCode of the instances being passed to the method, simple enough.

 

NHibernateSample.ModelMapper:

This is a very important project, here is where I’m using the Fluent NHibernate API to map our NHibernateSample.Model assembly against our database.
One of the cool things that the Fluent API provides to us is the use of conventions (following the “convention over configuration” spirit) that helps us to save a lot of time in the mapping process, for example, you may have a guideline for your database with regards to naming the primary key column of a given table, something like <Table_Name>ID, so, for the Product table you have ProductID table.
Using plain NHibernate mapping files you would have to go into the tedious work of map each of one entity, throwing away your convention.
Hopefully we are using Fluent NHibernate and this is easy cake.

This project has little classes that inherit from FluentNHibernate.Mapping.ClassMap which gives us all the facilities to configure our entities.
Lets take a look at our StateProvinceMapper class:

    public class StateProvinceMapper : ClassMap<StateProvince>

    {

        private const string schema = "Person";

        public StateProvinceMapper()

        {

            SchemaIs(schema);

            Id(x => x.StateProvinceID);

            Map(x => x.Name)

                .WithLengthOf(50)

                .ReadOnly();

            References(x => x.TerritoryID)

                .LazyLoad()

                .Not.Nullable();

        }

    }

As you can see is pretty straightforward.
1) We set the schema of this entity, which is the “Person” schema in the AdventureWorks database.
2) We set the Id of this entity, which is the StateProvinceID property that maps directly to the same column in the database table.
3) We map our Name property against the Name column in the database table, also, we set some attributes as its MaxLenght and also we say that this is a readonly property.
4) We set a reference with another entity using our TerritoryID property (of StateProvince type, which also maps to its corresponding table), also we set the LazyLoad attribute that says to NHibernate to do not retrieve it from the database until an explicit request is performed (stateProvinceInstance.TerritoryID.Name would fire a database query) and lastly we mark this property as Not-Nullable so in Update and Insert operations an attempt to store an StateProvince entity with a null value for its TerritoryID property will throw an exception.

The place in charge of build the mapping from our Model against the database is the ModelBuilder class (NHibernateSample.ModelMapper/ModelBuilder.cs), in there we are doing all the heavy work to create our mapping:

        private static void buildModel()

        {

            // initialize persistance configurer

            IPersistenceConfigurer persistenceConfigurer = getPersistenceConfigurer();

            // initialize nhibernate with persistance configurer properties

            cfg = persistenceConfigurer.ConfigureProperties(new Configuration());

            // add mappings definition to nhibernate configuration

            var persistenceModel = new PersistenceModel();

            persistenceModel.addMappingsFromAssembly(typeof(ModelBuilder).Assembly);

            persistenceModel.Conventions.GetPrimaryKeyName = x => x.Name;

            persistenceModel.Conventions.GetForeignKeyName = x => x.Name;

            persistenceModel.Configure(cfg);

 

            //Mix mode, this line allows us to append config settings to our configuration

            //instance from .config files (web.config,app.config)

            // or any other "traditional" (xml based) approach.

            //NOTE: If you are going to go with full Fluent configuration, you should remove the line below

            cfg.Configure();

 

        }

Look how we are saying that the GetPrimaryKeyName should be inferred directly from the property name and the same for the GetForeignName method, so, if we have a class Product, and we say that its ID is ProductID, its primary key should be mapped to the column ProductID as well, and the same for its references.

You can look deeper into the project to get a more detailed view of what is going on there.

 

NHibernateSample.LINQModel:

In this project we are using the NHibernate.Linq assembly to create a NHibernateContext which has implemented a LINQ provider (not as good as LINQ to SQL) that allow us to create queries in a LINQ to SQL fashion.
The main class there is the ModelContext class, which takes our entities and expose them as IOrderedQueryable implementations.
Is very simple, here is how it looks:

public class ModelContext : NHibernateContext

    {

        public ModelContext(ISession session)

            : base(session)

        {

        }

        public IOrderedQueryable<Customer> Customers

        {

            get

            {

                return Session.Linq<Customer>();

            }

        }

        public IOrderedQueryable<Address> Addresses

        {

            get

            {

                return Session.Linq<Address>();

            }

        }

 

        public IOrderedQueryable<AddressType> AddressTypes

        {

            get

            {

                return Session.Linq<AddressType>();

            }

        }

 

        public IOrderedQueryable<CustomerAddress> CustomerAddresses

        {

            get

            {

                return Session.Linq<CustomerAddress>();

            }

        }

 

        public IOrderedQueryable<SalesTerritory> SalesTerritories

        {

            get

            {

                return Session.Linq<SalesTerritory>();

            }

        }

 

        public IOrderedQueryable<StateProvince> StateProvincies

        {

            get

            {

                return Session.Linq<StateProvince>();

            }

        }

    }

As you can see, it takes an ISession (which is our NHibernate instance to handle the database management) and for each entity I’ve created a wrapper that returns the IOrderedQueryable that are going to allow us to work with them easily.

NHibernateSample.Tests:

As its name says, there are just a bunch of tests ( I’m using XUnit as my unit test suite) that I’ve build to show how our ModelContext class can be used to perform simple operations as projections or to create aggregates. I reckon that the tests in there sucks, I’m on the process of learning how to write proper tests, so this is not a good example of how a set of  unit tests should be written.
Lets move on and take a look at the AddressTests class, there I’ve the following test:

        [Fact]

        public override void Test_Retrieve_Entity_With_EntityID_Equals_To_X_Should_Return_Null()

        {

            int addressID = 0;

            using (var context = new ModelContext(Session))

            {

                var result = (from address in context.Addresses

                              where address.AddressID == addressID

                              select address).SingleOrDefault();

                Assert.Null(result);

            }

        }

As you can see, it’s very similar to what you can do using LINQ to SQL, but with NHibernate :)
This is another test from the same class:

        [Fact]

        public override void Test_Sorting_Descending()

        {

            using (var context = new ModelContext(Session))

            {

                var result = (from address in context.Addresses

                              where address.City == "Bothell"

                              orderby address.AddressID descending

                              select address).ToList();

 

                Assert.False(result.Last().AddressID > result.First().AddressID);

 

                foreach (var item in result)

                {

                    Console.WriteLine(item.AddressID);

                }

            }

        }


Very self-explanatory. You can check the other test to have some fun with the power (and several limitations) of the LINQ provider for NHibernate.

 

NHibernateSample.BusinessLayer:

This project is intended to be used for our web applications. I think that the interesting bits are related to the session management (NHibernateSample.BusinessLayer/SessionManagement/SessionManager.cs) and the use of StructureMap to configure our dependencies (NHibernateSample.BusinessLayer/Bootstrapper.cs, NHibernateSample.BusinessLayer/Repositories/ICustomerRepository.cs and NHibernateSample.BusinessLayer/Repositories/Implementations/CustomerRepository.cs).

 

NHibernateSample.CustomerWebSite:

This project shows how you can use  NHibernate to perform a basic CRUD operation over our Customer entity, I’ll try to find the time to create a more complex example (I can’t assure this :D), but with that simple aspx page you should be able to go on your own and make a nicer web app.
Some interesting things are happen in the global.asax file, and also it will help in the process to integrate asp .net controls with NHibernate (GridView, ObjectDataSource).

 

Finally, please don’t forget to update your database connection in order to run the samples. The file that you need to update is located in the Solution Items folder in the solution tree, is named hibernate.cfg.xml, you should change the value for the property connection.connection_string with one that match your environment.

    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">

        <session-factory>

            <property name="current_session_context_class">

                managed_web

            </property>

            <property name="connection.connection_string">

                Data Source=YOUR_DATABASE_SERVER_GOES_HERE;Initial Catalog=AdventureWorks;Integrated Security=True

            </property>

        </session-factory>

 

    </hibernate-configuration>

 

Please, if you find a WTF in the source code, don’t hesitate to send your feedback, I’ll be very thankful.

You can download the full demo here.

Bye bye.

1 comment:

Anonymous said...

nice tutorial. well written!