[You can catch up with previous posts on Rhinestone here.]

Okay, so based on my last post a rough domain model was defined as well as the database model. I’ve removed the previous Rhinestone.Shared project, and it’s related test project, as that has now been encapsulated in NCommon.

So the next step is to setup the mapping layer between the ORM framework of my choice and the database model. Since we I am going to use NHibernate in Rhinestone that involves setting up NHibernate and the mappings that will allow NHibernate to hydrate result sets returned from the database as our domain entities and in the inverse direction serialize our domain entities as records in the database, with their relationships and all.

What is Fluent NHibernate:

You can read the excellent getting started article on Fluent NHibernate here. Basically Fluent NHibernate is an alternateive way, an excellent alternative, to traditional xml mapping and configuration files that are used by NHibernate. The biggest advantage of Fluent NHibernate is that it provides a compile time checking that was not possible with Xml mapping files (although addins are available, especially for resharper, that perform a design time check). If you referenced a field name “Name” in your xml mapping file and that property was then renamed to FirstName and you forgot to update the mapping, that would not give you any kind of notification at compile time, in fact the .net compiler would happily build your binaries and the error would surface only at run time.

Now that I have provided enough of a marketing pitch for the Fluent NHibernate project, it must be noted that it’s very much in development (as of this writing). There are no binary releases as yet and if you want to get started using Fluent NHibernate you must get the latest source code and build it yourself. You might encounter bugs and if you do please do let the development team know, but the project is stable enough so that you could (and should) give it a try.

Defining a simple mapping with Fluent NHibernate:

After getting the source, building it and then referencing it in your project, starting to define mappings for your entities is very straight forward. I’ve created a new project called Rhinestone.Domain.Mappings (class library) and this referenced FluentNHibernate.dll. In this project I’ll define all the mappings for my domain model. The reason I am doing this is because I want to be flexible enough where if I want to use another ORM framework, then all I have to do is provide a new set of mappings that target the new framework and I’m golden. Besides, mappings don’t really belong under the domain model anyways.

image

So lets start defining a mapping for the Project domain entity. You start out defining a mapping be creating a class that inherits from ClassMap:

/// <summary>

/// Provides mappings for the <see cref="Project"/> domain entity.

/// </summary>

public class ProjectMap : ClassMap<Project>

{

 

}

Basically ClassMap forms the root of all mappings defined for a single entity, in this case the Project entity. When you inherit from ClassMap, mappings are defined in the constructor of your inherited class. Now, I’ll step through showing the same mappings defined in xml and then defined via ClassMap in Fluent NHibernate. A normal xml mapping file starts like so:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

                   assembly="Rhinestone.Domain"

                   namespace="Rhinestone.Domain">

 

</hibernate-mapping>

Now, the table in the database that we need to map the Project entity is called Projects. So here is the mapping for the Project entity in xml and then in PorjectMap:

<class name="Project" table="Projects">

 

</class>

/// <summary>

/// Default Constructor.

/// Defines mappings for the <see cref="Project"/> entity.

/// </summary>

public ProjectMap()

{

    WithTable("Projects");   

}

The WithTable method basically sets the underlying table name that the entity maps to.

Now, the first mapping that is normally provided in NHibernate is the identity property. This mapping defines what is the field / property that acts as the identity property of the entity and it’s mapping. In the Project class the identity field is ProjectID, which has only a getter so we need to define that NHibernate should access the underlying field instead of the field when setting it’s value. ProjectID is also an auto-generated filed which must also be specified in the mapping. Below is the xml mapping and after that the same mapping defined in ProjectMap:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

                   assembly="Rhinestone.Domain"

                   namespace="Rhinestone.Domain">

  <class name="Project" table="Projects">

    <id name="ProjectID" access=" nosetter.camelcase-underscore">

      <generator class="identity"/>

    </id>

  </class>

</hibernate-mapping>

/// <summary>

/// Default Constructor.

/// Defines mappings for the <see cref="Project"/> entity.

/// </summary>

public ProjectMap()

{

    WithTable("Projects");

    Id(prop => prop.ProjectID)

        .Access.AsReadOnlyPropertyThroughCamelCaseField()

        .GeneratedBy.Identity();

}

The Id method in ClassMap provides a way to define the property that acts as the identity property and then uses a fluent dsl to define additional details on the mapping. Fluent NHibernate uses lambdas to specify mappings, in the code above Id(prop => prop.ProjectID) tells fluent NHibernate to map the ProjectID property as the identity property of the entity. Using lambdas to define mappings instantly gives us an added benefit that if the underlying property is renamed, the mappings will be renamed as well (or at least give a compile time error).

Additionally, you can use the fluent DSL methods provided by Fluent NHibernate to provide additional details on the mapping, like in the example above the Access property. In the code snippet above, Access.AsReadOnlyPropertyThroughCamelCaseField instructs NHibernate to access this properties field that should have the name that matches the camel case underscore format. The thing to note here is that Fluent NHibernate already provides all available access strategy options which is nice because when I started out with NHibernate I always had to go back to the documentation to figure out the exact string format that should be used in the access attribute in the xml mapping file.

Okay moving on, mapping properties to the underlying columns is also fairly straight forward. You can do that using the Map function in ClassMap.

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

                   assembly="Rhinestone.Domain"

                   namespace="Rhinestone.Domain">

  <class name="Project" table="Projects">

    <id name="ProjectID" access=" nosetter.camelcase-underscore">

      <generator class="identity"/>

    </id>

    <property name="Code"/>

    <property name="Name"/>

    <property name="Description"/>

  </class>

</hibernate-mapping>

    /// <summary>

    /// Default Constructor.

    /// Defines mappings for the <see cref="Project"/> entity.

    /// </summary>

    public ProjectMap()

    {

        WithTable("Projects");

        Id(prop => prop.ProjectID)

            .Access.AsReadOnlyPropertyThroughCamelCaseField()

            .GeneratedBy.Identity();

        Map(prop => prop.Code);

        Map(prop => prop.Name);

        Map(prop => prop.Description);

    }

}

It’s that straight forward. In case the name of your property doesn’t match the underlying column name you can also use an overload of Map that accepts the column name that the property is mapped to:

    /// <summary>

    /// Default Constructor.

    /// Defines mappings for the <see cref="Project"/> entity.

    /// </summary>

    public ProjectMap()

    {

        WithTable("Projects");

        Id(prop => prop.ProjectID)

            .Access.AsReadOnlyPropertyThroughCamelCaseField()

            .GeneratedBy.Identity();

        Map(prop => prop.Code, "ProjectCode");

        Map(prop => prop.Name);

        Map(prop => prop.Description);

    }

}

In the next post I’ll complete the mapping for the Project entity by specifying mappings for a custom user type in NHibernate.

Posted on Thursday, February 12, 2009 12:00 AM | Filed Under [ NHibernate FluentNHibernate DDD Rhinestone ]


Comments

Gravatar
# re: Using Fluent NHibernate in Rhinestone – Part I
Posted by Ugg australia
on 9/25/2011 11:08 PM
NICE WORK
Gravatar
# re: Using Fluent NHibernate in Rhinestone – Part I
Posted by FranciscoRios
on 3/21/2012 11:05 PM
Post Comment
Title *
Name *
Email
Url
Comment *  
Please add 8 and 6 and type the answer here: