LA.NET [EN]

Oct 24

If you’re a NHibernate user, you’ve surelly heard about the Fluent NHibernate, a project that allows you to define the mappings by using a fluent API. I didn’t really had the time for testing it until yesterday. Why did I only tested it yesterday? Simple: because I had to perform some major refactorings on the current project I’m working and that meant having to go through the XML mappings files and changing all those damn properties by hand. Yes, it was the perfect excuse for introducing the fluent mapping in my project.

Overall, I’m pleased with it, but since there really aren’t many docs on how to use them, I thought it would be a good idea to give some examples of its use here and to point one or two gotchas that you might get while using it. Before using it, do keep in mind that there are some options which aren’t implemented yet (but I think it’s fair to expect them to be implemented in a near future). Having said this, it’s time to show some examples. Lets start by building a dumb class and call it Entity:

class Entity{
  public Int32 Id{ get; private set; }
  public Int32 Version{ get; set; }
  public String Name{ get; set; } 
}

We’ve got an ID, a version and a property. Lets map them to columns of a table called Customers, without lazy loading:

class EntityMapping: ClassMap<Entity>{
  public EntityMapping(){
     WithTable( “Customers” ); //set table name
     SetAttribute( “lazy”, “false”); //no lazy loading
     Id( ent => ent.Id,“IdCustomer” ) //Id prop into column IdCostumer
       .WithUnsavedValue(0)
       .SetGeneratorClass(“identity”);
     Version( ent => ent.Version).TheColumnNameIs(“MyVersion”);
     Map( ent => ent.Name,“CustomerName”)
       .WithLenghtOf(200)
       .CanNotBeNull();
  }
}

This basic mapping introduces several important concepts. All the configuration classes should inherit from ClassMap<T>. Setting the table name is easy: just call the WithTable method and that’s it. You can also use the SetAttribute method for setting up the other attributes you would normally set on you <class> element. In the previous example, I’ve just used it to change the default lazy loading behaviour.

Setting the Id and Version properties are easy too: just call the Id and Version methods. Do notice that you didn’t really need to write all that code if you’re using the defaults (I never know which is which and that is why I generally end up writing everything I remember :))

Simple properties are mapped through the Map method. Notice that in the previous example we indicate all the column names because they’re different from the properties names we’ve been using.

First rant: I really don’t like calling these methods from the constructor because we’re talking about virtual methods. Unfortunately, the current version doesn’t have any other hook I can use for setting up the mappings.

Second rant: SetAttribute retuns void, which means that if you want to call it several times, you can’t use a fluent approach.

Ok, let’s move on. Now I want to add a collection of entities to my entity. In this case, Entity can have several Branches and  Branch belongs only to one entity. Here’s the necessary changes to the Entity class:

class Entity{
  //previous code
  private ISet<Branch> _branches;
  public ISet<Branch> Branches  {
     get { return new ImmutableSet<Branch>(_branches); }
     private set{ _branches = value;}
  } 
}

For now, you just need to keep in mind that Branch is an entity with some properties and that it has its own configuration file. You can easilly map this relationship by using code similar to this:

class Mapping: ClassMapping<Entity>{
    public Mapping() {
     //previous code
     HasMany<Branch>(ent => ent.Branches)
                .AsSet()
                .Cascade
                .All()
                .WithKeyColumn("IdEntidade");
  }
}

As you can see, you specify a set by calling the AsSet method and then, if you want, you can also set the cascade and key column name. You’ll also find other AsXXX methods that you can use for the other types of collections (ex.: bags).

Another thing which you’ll need to represent is many-to-one relationships. For instance, suppose we’ve updated the Entity class so that it looks like this:

class Entity{
  //previous code
  public DomainAction Action{ get; internal set; }
}

DomainAction is another entity which has its own table. The References method can be used here for mapping the many-to-one relationship between Entity and DomainAction:

class EntityMapping: ClassMap<Entity>{
  public Mapping() {
     //previous code
     References( ent => ent.Action, "ActionId")
               .Cascade
               .SaveUpdate();
  }
}

When you get the mappings, you’ll see that the Customer table will have a column called ActionId, which holds the ID of the associated Action. Ok, pretty similar to the previous configuration code, right? Oh. lets add a component to our entity. We’ll call it Address:

class Entity{
  //previous code
  public Address Address{ get; set; }
}

Address is a class that implements what I like to call the value object pattern. Just by looking at the mapping code, you should be able to see what’s going on:

class EntityMapping:ClassMap<Entity>{
  public EntityMapping(){
    //previous code
      Component<Address>(branch => branch.Address,
                              address =>
                                  {
                                      address.Map(a => a.Street, "St")
                                          .WithLengthOf(300);
                                      address.Map(a => a.ZipCode, "ZC")
                                          .WithLengthOf(100);
                                      address.References(a => a.CivilParish)
                                          .TheColumnNameIs("IdParish")
                                          .Cascade.None()
                                          .SetAttribute("lazy", "false");

                                  }
               );
   }
}

As you can see, we start by indicating that the Address property points to a component and then we need to specify the mappings between the columns of the table and each of the properties of that component class. Nothing really new there, right? Ok, so lets make things more interesting. Suppose we’ve got a collection of components…a good example might be a Contacts property, that returns a collection of Contact objects on the Entity class. That means we could have something like this:

class Entity{
  //previous code
  private ISet<Contact> _contacts;
  public ISet<Contact> Contacts
  {
            get { return  new ImmutableSet<Contact>(_contacts); }
            internal set { _contacts = value;}
  }
  //methods for adding/removing contacts not shown here
}

Now, the interesting part: mapping the properties to the database:

class EntityMapping: ClassMap<Entity>{
  public EntityMapping(){
     //previous code
     HasMany<Contact>(branch => branch.Contacts)
                .AsSet()
                .WithTableName("Contacts")
                .WithKeyColumn("IdEntity")
                .Component(ct =>
                               {
                                   ct.Map(c => c.Kind, "ContactType");
                                   ct.Map(c => c.Value, "Contacto");
                               });
  }
}

If break it apart, we can see that:

  • we have a set that should be kept on a table called Contacts;
  • We’re also creating a foreign key called IdEntity;
  • And then, the important part: we’ve got a collection of components!

I hope that by now I’ve convinced you on using this API. Just to make sure you see what I mean, lets add add some inheritance, ok? Lets suppose we have two new classes (Individual and Company) that expand the previous Entity class:

class Individual: Entity{
  //some properties go here
}

class Company: Entity{
  //it can also be a new type, with no properties
}

Since I wanted to keep both entities on the same table, I’ve ended up writing this on the mapping class:

public class EntityMapping:ClassMap<Entity>{
  //previous code
  DiscriminateSubClassesOnColumn("EntityKind",
                                             (Int32) (EntityKind.Single))
      .SubClass<Individual>()
      .IsIdentifiedBy((Int32) (EntityKind.Single))
      .MapSubClassColumns(e =>
        {
          // code for mapping the properties of derived class
         })
       .SubClass<Company>()
       .IsIdentifiedBy((Int32) (EntityKind.Company))~
       .MapSubClassColumns( e => { } );
}

What are we doing here? First, we’re saying that the table has a column named EntityKind which is used as a discriminator and we’re also setting its default value (I’m casting the enum to integer because that’s the type of my column on the database). Each subclass is introduced by the Sublass method and you’ll also need to pass the values that identify each instance of the derived type (notice the method IsIdentifiedBy call). If you have properties on the derived class, you can map them into the table by calling the MapSubClassColumns method. Notice that even if the new type doesn’t add new properties, you still need to call the MapSubClassColumns method over that subclass (as it’s done in the Company subclass).

Rant Three: Pay attention to the place where you call the DiscriminateSubClassesOnColumn method (it looks like there’s a bug on the way items are compared while ordering the several elements that are maintained internally by the mapping class). In my sample, I had to put it after the Version method. Putting it before resulted in getting the <discriminator> element after the <version>, and that means getting an exception while loading the XML for that class.

By now, we’ve already touched several things you’ll use in a NH application. There’s still one thing missing: how do we load the definitions from the new classes? One thing you can do is use reflection to load the configuration classes. Here’s some code you can probably reuse for doing that (it’s not really complete; I’m only putting it here to present some concepts):

//get NH Configuration object filled with info that generally
//comes from cfg file
var configuration = GetConfigurationWithDialectConnectionStringEtc();
AddTypesToConfiguration( configuration );
var factory = configuration.BuildSessionFactory();
//from here you can get the ISession you need…

The AddTypesToConfiguration method uses reflection to load the types. It looks something like this:

private void AddTypesToConfiguration(Configuration configuration) {
  //need to get a reference to the assembly where the mapping files are
  var currentTypes = GetAssemblyWithMappingTypes(); 
  var methodsThatReturnXmlDocs = currentTypes
        .Where( existingType => GetMethodForExecution(existingType) != null)
        .Select(existingType => GetMethodForExecution(existingType))
        .ToList();
        //probably could improve this code, but I’ll leave it for you…
        foreach (var method in methodsThatReturnXmlDocs) {
           var doc = method(new MappingVisitor());
           configuration.AddDocument(doc);
        }
}

The GetMethodForExecution type returns a delegate that points to the method that will return the XML document with the mappings:

private Func<IMappingVisitor, XmlDocument>
                                       GetMethodForExecution(Type currentType) {
  //must be a non abstract, non generic class
  //with public instance constructor
  //again, this could probably be improved,
  //but that’s not my objective here…
  if (currentType.IsClass && !currentType.IsAbstract &&
       currentType.GetInterface(typeof(IMapping).FullName) != null &&
       !currentType.IsGenericType && 
       currentType.GetConstructor(Type.EmptyTypes) != null) { 
            var instance = Activator.CreateInstance(currentType);
            var methodInfo = currentType.GetMethod("CreateMapping");
            var method = (Func<IMappingVisitor, XmlDocument>) 
                                  Delegate.CreateDelegate(
                                     typeof (Func<IMappingVisitor, XmlDocument>),
                                     instance,
                                     methodInfo,
                                     true);
             return method;
         }
      return null;
}

All mapping classes implement the IMapping interface and that’s why I’m using that so see if the current type has mapping information. After getting a reference to a valid mapping type, I’ll try to get a reference to its CreateMapping method because that method returns an XmlDocument with the mapping information that will be added to the NH Configuration object.

So that’s it. There are still some more things I could talk about here, but these were the main topics I’ve learnt while building my sample. Even though there are still some bugs, I believe that I will keep using this famework in future projects.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>