Fluent NHibernate samples – Auto mapping (Part 1/2)

In my previous blog post, I have announced the sample solution with which I try to provide code sample for very comprehensive documentation which can be found on http://fluentnhibernate.org/..

The project is hosted on CodePlex (http://fnhsamples.codeplex.com/). Right now it contains just a small sample which I would use in this blog post but in the future I intend to grow it until I wouldn’t cover most of the interesting features FNH offers.

The purpose of project is just to demo how fluent nhibernate mappings work so you can quickly “get them” and NOT:

  • to teach on how NHibernate works (buy this book for that)
  • to teach you in detail about fluent nhibernate (go to http://www.fluentnhibernate.org for that)
  • to teach about best practices in abstracting NHibernate dependencies (you can find that here)
  • to teach about best practices in domain modeling etc

I am also by no means an expert in neither nhibernate nor fluent nhibernate. In fact I am just a grunt like many of you reading this blog post who was searching for similar blog post when he was banging his head against the wall trying to learn how to use it – 1+ year ago very little docs) so take EVERYTHING I say with a grain of salt.

I am also aware of the state of my English, but I am really doing my best and if anyone wants to help editing the blog post I would put that version in code plex 🙂

So, let’s start…

An example of Fluent NHibernate auto mapping in action

So, here’s the domain model I’ll be using in this blog post to show couple of FNH auto mapping aspects

image

And here’s the database model which would be created after the sample would be executed based on fluent nhibernate auto mapping conventions.

image

(To get more details about the domain design check the use case description from previous blog post)

Convention over the configuration

imageFNH auto mapping works based on applying the convention over the configuration which I usually try to explain like this…

“There is a set of rules which would be applied to your domain during its mapping to database model.

Here are couple of examples of rulesconventions:

  • Database table would be named used plural form of the entity name.
  • Primary key of every table would be named following the rule “entity name” + “ID”

Fluent NHibernate comes with a default set of rules which you can customize to your own preferences on a very cool and easy way.

Sounds simple? It is THAT simple.”

Let’ see quickly how the fluent nhibernate magic happens.

How the Fluent NHibernate Auto mapping magic works (explanation for us others)?

I won’t go deep into the details (for that go to http://fluentnhibernate.org or How FNH works?) but in general it is based on two design patterns: Proxy and Visitor.

If you are not familiar with the patterns here’s a simple way for you to get them in the context of fluent nhibernate magic.

The role of proxy design pattern in fluent nhibernate

If you check out some of the entities in Vuscode.FNHSamples.Domain project you would see that all of them are non sealed classes with all of the members being virtual…  So, the code like this

namespace Vuscode.FNHSamples.Domain
{
    public class Address
    {
        public virtual string Email { get; set; }

        public virtual string City { get; set; }

        public virtual string Country { get; set; }
    }
}

The reason why we HAVE TO respect this rules designing our domain classes is related to the fact that FNH uses castle dynamic proxy functionalities to (in overly simplified version) create an “in memory” proxy child class by inheriting the real one and overriding the properties in the proxy child class in order to enable intercepting their calls.

In this example therefore inside of the FNH engine there would be created a “ProxyAddress” class inheriting from the Address class but which would have implemented additional interfaces and override members effectively adding during the run time behaviors and shapes to original Address class. That’s how a POCO can be achieved: we don’t need any attributes, no special base class or base interface etc..

Now, in order to understand why FNH needs this we need to take a quick peek at how FNH “mapping rules” (properly called conventions) are implemented.

How the fluent nhibernate conventions are implemented?

Always on the same way (thanks to brilliant work of FNH authors): always inherit and implement a special interface which has a method accepting a parameter of certain interface type.

    public class ClassConvention : IClassConvention
    {
        public void Apply(IClassInstance instance)
        {
            // do something with instance
        }
    }

The reason why  our convention has to implement certain interface is due to the fact that during the run time fluent nhibernate would iterate over all of the types of the given assembly and collect “all of the types implementing the IClassConvention” thus “collecting the rules”.

The reason why a IClassInstance parameter was passed is that the Apply method would get SOMETHING implementing that interface without knowingcaring about what that something really is.

This design approach where you enable your class to work with various entities without coupling to its concrete implementation can be roughly called visitor pattern.

If I use gain the same sample of Address and “AddressProxy” class, imagine that AddressProxyClass created on the fly implements the IClassInstance interface. Wouldn’t that enable us to pass an instance of addressProxy class to ClassConvention Apply method so it could perform its functionality on it? 🙂

The end result of those two patterns is that instance Address class ends inside of the Convention Apply method without adding anything to domain other then virtual keywords on properties.

Iterating, iterating, iterating…

During the runtime mapping process FNH (overly simplified) iterates over all of the types and creates their proxies.

Every proxy gets added certain interfaces which define methods allowing “outer world” to alter the state of proxy.
Fluent NHibernate (or user) then creates a collection of conventions defining the rules how certain aspects of proxies should be altered.

Now the code iterates every proxy and for every proxy it iterates over all of the conventions and applies the one matching the proxy.

As the end result of that iteration, we gat all of the proxies with their state sets up in proper state.

Then FNH iterates all of the proxies again and translates states of each one of them to NHibernate required XML representation.

Brilliant, isn’t it?

Back to reality

Now when I (hopefully) explained how NHibernate works in layman’s terms, we can just go over the conventions I have in my sample and provide explanation what is the relationship between them with certain pieces of my sample.

Class Convention

This is convention which tells to Fluent NHibernate how to map entities to database tables.

I have only one rule related to that:”A table name should be plural form of the entity name”, so the code doing that is pretty simple

namespace Vuscode.Framework.NHibernate.Conventions
{
    using FluentNHibernate.Conventions;
    using FluentNHibernate.Conventions.Instances;

    public class ClassConvention : IClassConvention
    {
        public void Apply(IClassInstance instance)
        {
            instance.Table(Inflector.Pluralize(instance.EntityType.Name));
        }
    }
}

IClassInstance has two key members (key in sense of this sample):

  • EntityType – providing access to a type being mapped to database table
  • Table(name) – method which sets the value of the table name.

(To explore capabilities outside of my sample use intellisense which in case of fluent interfaces is your best friend)

Inflector is just a helper class I took from Castle.ActiveRecord project (been a long time ago) and which purpose is to get plural form of a given string. I put it also in sample project so you can check it out if you wish.

So, now when we know all of the pieces we can read the implementation inside of Apply method like this

“Make sure that whatever the proxy was sent it would be mapped in a data table which name would be plural form of the original class proxy was created from”

(Due to the fact every convention is implemented in same manner implement a interface and get something injected I’ll skip repeating that in other conventions)

DefaultStringPropertyConvention

This is convention which tells how class string properties should be mapped in database column.

My rules are simple: default length 100 and every string can be null value.

namespace Vuscode.Framework.NHibernate.Conventions
{
    using FluentNHibernate.Conventions;
    using FluentNHibernate.Conventions.Instances;

    public class DefaultStringPropertyConvention : IPropertyConvention
    {
        public void Apply(IPropertyInstance instance)
        {
            instance.Length(100);
            instance.Nullable();
        }
    }
}

Foreign Key Convention

This is convention which defines how fluent nhibernate should behave while mapping association properties to foreign keys.

My rule is simple:”Name of the foreign key is name of the table being referenced + ID suffix”

Here’s the code from sample

using System;

using FluentNHibernate.Conventions;
using System.Reflection;

namespace Vuscode.Framework.NHibernate.Conventions
{
    public class CustomForeignKeyConvention : ForeignKeyConvention
    {
        protected override string GetKeyName(PropertyInfo property, Type type)
        {
            return property == null
                    ? type.Name + "ID"
                    : property.Name + "ID";
        }
    }
}

As you can see from the code not exact translation of my rule so it needs some additional clarification…

The GetKeyName method accepts two parameters:

  • property (holding a pointer to a property in entity referencing the “parent” entity
  • type (holding a pointer to a  “parent” table)

If we check out the resulting DB diagram

image

and how the domain implementation of Blogs looks like

using System.Collections.Generic;

namespace Vuscode.FNHSamples.Domain
{
    public class Blog : Entity
    {
        public virtual Author Author { get; set;} // component

        public virtual BlogRoll Roll { get; set; } // references

        public virtual IList Posts { get; set; } // has many

        public virtual string BlogTitle { get; set; }

    }
}

We can clearly see that due to the fact that Blog has a Roll property pointing to parent BlogRoll, FNH took that property value + “ID” and created RollID foreign key in Blogs data table. So, that explains how FNH works in FK convention when property being sent is with non null value and leaves us with the question “how come that value can be null”?

To answer that, let we check out the other part of the resulting UML diagram representing DB interpretation of the Author class inheritance

image

As you can see, GuestAuthor and RegularAuthor have their foreign keys named “AuthorID” even none of those two has an explicit “parent” property like in previous case.

In other words There is no GuestAuthor.Author and RegularAuthor.Author properties but we still have the need for defining FK in their tables.

In this type of cases, ForeignKeyConvention would get a null propertyInfo value (because there is no property) and a pointer to a entity to be used with defining of database FK (in this example Author). That’s how in my sample foreign key of those tables become

Many to Many convention

This is convention which defines how fluent nhibernate should behave while mapping the N – N relationships where a class A has a collection property of class B type and the class B has a collection property of class A.

Here’s the code sample from the Vuscode.FNHSamples.Domain –> Post and Category classes

namespace Vuscode.FNHSamples.Domain
{
    using System.Collections.Generic;

    public class Post : Entity
    {
        public virtual IList Categories { get; set; }  // has many to many

        public virtual string Title { get; set; }

        public virtual PostStatus Status { get; set; }

    }
}

A Post can have many Categories

namespace Vuscode.FNHSamples.Domain
{
    using System.Collections.Generic;

    public class Category : Entity
    {
        public virtual IList Posts { get; set; } // has many to many

        public virtual string Name { get; set; }
    }
}

One Category can be used in many samples.

I prefer mapping Many to many relationships using the Association Table Mapping pattern where additional table is created with two foreign keys columns matching the primary keys of the associated tables.

Here’s how it looks in resulting database model with PostsToCategories table being association table.

image

I guess after seeing the diagram it is quite obvious to get the many to many convention I have:

Name of the association class should be like “TableNameA” + “To” + “TableNameB”.

How NOT to implement many to many relationship

As you can read in great detail here, many to many is in general combination of two 1 – N relationships which if it would be done like this

namespace Vuscode.Framework.NHibernate.Conventions
{
    using FluentNHibernate.Conventions;
    using FluentNHibernate.Conventions.Instances;

    public class ManyToManyConvention : IHasManyToManyConvention
    {
        public void Apply(IManyToManyCollectionInstance instance)
        {
            instance.Table(
            	string.Format("{0}To{1}",
                        Inflector.Pluralize(instance.EntityType.Name),
                        Inflector.Pluralize(instance.ChildType.Name))
		);
        }
    }
}

Would result in next database diagram state

image

So, we have 2 associations tables where each one of them covers their own path.

Clearly this is an overkill from Db perspective due to the fact that the same table can be used in both paths.

In NHibernate parlance that is achieved using Inverse relation type (again, you can read about it in great detail here) which in layman’s terms can be explained “when you need to map the Post –> Categories relation, pleas use the already defined Categories –> Post and just revert it”

And that’s exactly what the actual implementation in my code sample does

Here’s the code

Let see how this was implemented in the sample code

namespace Vuscode.Framework.NHibernate.Conventions
{
    using FluentNHibernate.Conventions;
    using FluentNHibernate.Conventions.Instances;

    public class ManyToManyConvention : IHasManyToManyConvention
    {
        public void Apply(IManyToManyCollectionInstance instance)
        {
            if (instance.OtherSide == null)
            {
                instance.Table(
                    string.Format(
                        "{0}To{1}",
                        Inflector.Pluralize(instance.EntityType.Name),
                        Inflector.Pluralize(instance.ChildType.Name)));
            }
            else
            {
                instance.Inverse();
            }
        }
    }
}

The instance.OtherSide is null in situation when there is no already defined relationship between EntityType and ChildType. In that case code uses Table method to set the name of association table respecting my naming convention TableA name + “To” + TableB name. That first if would result with PostsToCategories association table being created.

Now the FNH would iterate more (as described above) and the Post –> Category relation would be processed. When this happens, instance.OtherSide would NOT be null so instead of creating new association table FNH would map that relation as inverse to the original one.

Conclusion

This blog post become really long so I have decided to split it in two posts. In next post I’ll show a few more conventions and process of fluent configuration with switches I’ve been using in my sample

Stay tuned 🙂

Advertisements

Posted on November 4, 2009, in Uncategorized. Bookmark the permalink. 3 Comments.

  1. Nikola,
    This is a great explanation, and your sample project is the ONLY one I've been able to find that you can download, and it "just works".
    My only (slight) reservation is that it might be a bit intimidating for the FNH newbie (like me) who probably would be content to use the default conventions, and may not need subclassing, etc.
    On the other hand, it's great that you demonstrate these more advanced techniques in a complete, working example.
    Nice job!

  2. Tom,
    My whole idea was to start with something and then based on ideas (like yours) evolve that to a set of examples covering most of the thing people care for in every day work (famous 80% case)
    I’ll try to do tommorow the simplest possible example (as the one you have asked for) and upload it to the code plex project so everyone can check it out
    Stay tuned 🙂

  3. Great article!  Great Explanation – the best I have seen regarding latest FNH code and automapping.
    However I have a question:  The CategoriesToPosts Table is not filled when I do:
    using(var tx = session.BeginTransaction())
               {
                   //ABSTRACT CLASS:  var Aut = new Author { Name = "Heiko" };
                   //Aut.Adress = Adr;
                   var adr = new Address {City = "Berlin" , Country ="GER", Email="HeikoATgmx.de"};
                   var gAuth = new GuestAuthor{Name="Sebastian", OriginalBlogAddress="httpXY2"};
                   gAuth.Address = adr;
                   gAuth.LastModified = DateTime.Now;
                   var pst = new Post {Status=PostStatus.Active, Title="Post-NEW"};
                   var pst2 = new Post { Status = PostStatus.Inactive, Title = "Post-XXX" };
                   var Catg = new Category { Name = "Category_A" };
                   var Catg2 = new Category { Name = "Category_B" };
                   Catg.Add(pst);  //MANY
                   Catg2.Add(pst2);  //MANY
                   var RegAuth = new RegularAuthor { Name = "Heiko" };
                   RegAuth.Address = adr;
                   RegAuth.DateOfFirstBlogPost = DateTime.Now;
                   RegAuth.LastModified = DateTime.Now;
                   var rl = new BlogRoll { Name = "blogrollname" };
                   rl.LastModified = DateTime.Now;
                   var blg = new Blog {BlogTitle="HeissesZeugBlog"};
                   blg.LastModified = DateTime.Now;
                   blg.Author=RegAuth;
                   blg.Add( pst  );  //MANY   – does ps.Add(blg) inside
                   blg.Add( pst2 );  //MANY
                   blg.Roll = rl;
                   session.Save(blg);
                   session.Save(gAuth);
                   session.Save(rl);
                   session.Save(blg);
                   session.Save(pst);
                   session.Save(Catg);
                   //session.Save(Catg2);
                tx.commit
    Please Help

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: