Aug 25 2009

NerdDinner with Fluent NHibernate Part 2 – The mapping

Category: Uncategorizedbengtbe @ 06:00

This is the second post in a series of three where I’m going to see how we can change the NerdDinner project to use Fluent NHibernate instead of LINQ to SQL:

Introduction

In the first post we took a look at the domain model of NerdDinner.com, and recreated and improved the code that was auto generated by the LINQ to SQL designer. In this post we are going to look at how to map this domain model to the database using Fluent NHibernate.

Fluent NHibernate

Fluent NHibernate gives you an alternative to NHibernate’s XML mapping files. It lets you write mapping in strongly typed (and ReSharper friendly) C# code. In order to map an entity, you create a mapping class that derives from ClassMap<T>. All the mapping code is done inside the constructor by calling methods from the base class.

Last week the Release Candidate for Fluent NHibernate 1.0 was released. The code in this post has been updated with the changes in this release.

The mapping for the Dinner entity

The code for DinnerClassMap is shown below:

public class DinnerClassMap : ClassMap<Dinner>

{

    public DinnerClassMap()

    {

        Table(“Dinners”);

        Id(d => d.DinnerID).GeneratedBy.Identity();

        Map(d => d.Title).Not.Nullable().Length(50);

        Map(d => d.EventDate).Not.Nullable();

        Map(d => d.Description).Not.Nullable().Length(256);

        Map(d => d.HostedBy).Not.Nullable().Length(20);

        Map(d => d.ContactPhone).Not.Nullable().Length(20);

        Map(d => d.Address).Not.Nullable().Length(50);

        Map(d => d.Country).Not.Nullable().Length(30);

        Map(d => d.Latitude).Not.Nullable();

        Map(d => d.Longitude).Not.Nullable();

        HasMany(d => d.RSVPs).KeyColumn(“DinnerId”).Cascade.All();

    }

}

Explaination of code:

  • The Table method maps “Dinners” as the name of the table. By default Fluent NHibernate assumes it to be “Dinner”.
  • The Id method maps DinnerId as the primary key, and specifies that an identity column in SQL Server is used to generate ids.
  • The Map method is used to map simple properties to columns.
  • The HasMany method maps the one-to-many relationship to the RSVP table. Cascade.All() is used to make sure that RSVPs are saved/updated/deleded when the dinner is saved/updated/deleded.

The RSVP mapping

The code for the RSVPClassMap is shown below:

public class RSVPClassMap : ClassMap<RSVP>

{

    public RSVPClassMap()

    {

        Id(r => r.RsvpID).GeneratedBy.Identity(); ;

        Map(r => r.AttendeeName).Not.Nullable().Length(30);

        References(r => r.Dinner, “DinnerId”).Not.Nullable();

    }

}

Explaination of code:

  • No need to call the Table method, since Fluent NHibernate correctly assumes that the table name is “RSVP”.
  • The References method maps the “other side” of the HasMany relationship in the DinnerClassMap.

Is all this mapping code needed?

The mapping code shown above contains a lot of information about the database schema. In this case, where we just wanted to map the domain to an existing database we could remove the following:

  • Not.Nullable()
  • Length(int length)

In Greenfield projects I prefer to start with the domain, and then write the mapping, and finally automatically generate the database schema. You then need to include this information in the mappings. In the post Mapping a Twitter like domain with Fluent NHibernate I showed how you generate the database from the mapping.

If you have an existing database you can also use this to troubleshoot your mapping code. Generate a new database from your schema and check it against the existing database.

Give me a new identity!

NerdDinner uses the identity column of SQL Server as primary key. In most cases this works just fine, however it can cause problems with the Unit of Work functionality of NHibernate. If I designed this application from scratch I would rather choose the Guid.Comb or HiLo algorithm to generate primary keys.

If you want to read more about this, check out the post NHibernate POID Generators revealed.

Do you prefer to live in XML hell?

If you miss the good old days of XML (???), then Fluent NHibernate can help you with this. The code below shows how to export your Fluent Mappings to XML-files:

[TestMethod]

public void ExportMappings()

{

    FluentConfiguration conf =

       NHibernateConfiguration.CreateConfiguration(false);

    conf.Mappings(m =>

    {

        m.FluentMappings.ExportTo(@”PATH_TO_EXPORT_FOLDER”);

    });

    conf.BuildSessionFactory();

}

This technique is actually quite useful for several reasons:

  • First, if you are skeptical about using Fluent NHibernate because it has not reached 1.0, or because it might not support all mapping options, you can easily switch back to XML-files later.
  • Secondly, it can also be useful to troubleshoot mapping problems, because there is currently more information on the web regarding XML-mapping.

finally{}

In this post we have taken a look at how to use Fluent NHibernate to specify the mapping between the domain model and the database. In the next post we will take a look at the rest of the changes that was necessary in order to use the new domain and Fluent NHibernate.

If you liked this post then please shout and kick me :)

kick it on DotNetKicks.com Shout it

Tags: , , ,

4 Responses to “NerdDinner with Fluent NHibernate Part 2 – The mapping”

  1. Lars Mæhlum says:

    Nice post, as always. :)

  2. Atanas Hristov says:

    Thank you!

  3. dataCore says:

    thx 4 this post!

    is there any way to do the "existing database 2 nhibernateWithFluentMapping". A generator to create the domain model + mapping from an existing db?

  4. Bengt Berge says:

    Hi dataCore,

    I don’t know of any tools that can generate fluent-mappings. However you can use a tool like MyGeneration to generate the domain and the xml-mapping. Since fluent- and xml-mapping can live side by side, you can then gradually replace the xml-mapping with fluent.

Leave a Reply