Thursday, 15 July 2010

XML-free convention based compiled mappings WITHOUT Fluent NHibernate – Part 1

Fluent NHibernate is a very popular framework, but for me, it has a few issues. I find the API somewhat hard to discover (it is an abstraction over the XML configuration which I know well), and sometimes features I really want aren’t implemented, or take some time to arrive. This of course isn’t the FNH teams fault, but FNH has a huge scope and the extension points aren’t always there.

I ended up writing my own system for typed mappings that I feel is simpler, and allows you to build a mapping framework that does exactly the job you need it to. This series of posts will introduce the approach.

Given the formula domain assemblies + automapping framework = nhibernate mapping.xml it is obvious we will need to somehow manipulate and produce an nhibernate mapping xml file in a structured way, using c# code. The way I do this is to use the LINQ To Xsd project to generate  a statically typed representation of an NHibernate mapping file. Here is a simple mapping file, with the classic xml mapping on the left (thanks fincher.org), and Linq To Xsd mapping on the right:

xml vs linqtoxsd

You can see how similar the xml and the code are. This allows you to use easily migrate from xml mapping to code mappings. We can get rid of magic strings and make the mapping refactor proof very easily, e.g. by replacing "NHibernatePets.Pet, NHibernatePets" with typeof(Pet).AssemblyQualifiedName, and using static reflection to get the property names.

To try this out, download nhibernate-configuration.cs and nhibernate-mapping.cs (the LINQ to XSD generated files) and include them in your project, then bootstrap your NHibernate configuration using this snippet:

public static Configuration GetConfiguration(string connectionString)
{
    var cfg = new Configuration();
    var mappingXDoc = new hibernatemapping()
    {
        //add your mappings here
    };
 
    cfg.SetProperty(NHibernate.Cfg.Environment.Dialect, "NHibernate.Dialect.MsSql2008Dialect");
    cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, "NHibernate.Driver.SqlClientDriver");
    cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionString, connectionString);
    cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionProvider, "NHibernate.Connection.DriverConnectionProvider");
    cfg.SetProperty(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName);
    
    cfg.AddXml(mappingXDoc.ToString());
 
    return cfg;
}

Now you should be able to get started with writing typed mappings. Next time we’ll get started on conventions.

5 comments:

  1. i think part of the point is having the property tied to a property on the POCO object. name = "PetName" has the same problems as the Xml, it doesn't get refactored.
    ReplyDelete
  2. as mentioned above, you can use static reflection to bind the property name in a refactor-proof way.

    Stick with the series though, the automapping conventions will mean you don't even need to write any strings.
    ReplyDelete
  3. Such a shame you put this effort into something of your own instead of contributing to the Fluent NHibernate project on the areas where you felt it was coming short. I am pretty sure that the team would welcome patches with open arms.
    ReplyDelete
  4. Mark, it took me a day or so to write the foundations of my automapping framework - a lot less than it would have taken to learn enough about FNH to patch it.

    FNH offers a lot - fluent configuration and pre-defined conventions for pretty much the whole gamut of mappings. That's not what I'm offering, this is a series on a DIY/YAGNI approach to writing your mappings.

    (For the record, I did suggest Linq to XSD for generating the model schema to the FNH team a while back, but they already had something similar in the pipeline so it wasn't required)
    ReplyDelete
  5. Don't stop and go ahead even if somebody will say you that your work is unneeded.
    Make public your work in some place (CodePlex, GoogleCode, bitbucket, github... where you want).
    Please contact me if you want cross post in www.nhforge.org
    ReplyDelete