Introducing Fluent NHibernate

A couple of people have already covered this already, specifically Bobby Johnson, Matt Hinze, and Zachariah Young. I figure I should say something on it anyway.

I’ve adopted a project from Jeremy Miller that I think has the potential to be a really useful tool. It’s called Fluent NHibernate, and it’s primarily a fluent API for mapping classes with NHibernate.

We’re all well aware how awesome NHibernate is, but I think we all also have a bit of a dislike for the amount of XML you need to write to get your classes mapped; not only that, but also how the mappings are distinctly separate from the rest of your application. They’re often neglected and untested. One of the core tenets of the project is that we need a more succinct, readable, and testable way of writing your mappings.

The API

Take the following simple hbm file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Eg" assembly="Eg">

    <class name="Customer" table="Customers">
        <id name="ID">
            <generator class="identity" />
        </id>

        <property name="Name" />
        <property name="Credit" />

        <bag name="Products" table="Products">
            <key column="CustomerID"/>
            <one-to-many class="Eg.Product, Eg"/>
        </bag>

        <component name="Address" class="Eg.Address, Eg">
            <property name="AddressLine1" />
            <property name="AddressLine2" />
            <property name="CityName" />
            <property name="CountryName" />
        </component>
    </class>
</hibernate-mapping>

Then compare it to the same mapping, created using the fluent API:

public CustomerMap : ClassMap<Customer>
{
  public CustomerMap()
  {
    Id(x => x.ID);
    Map(x => x.Name);
    Map(x => x.Credit);
    HasMany<Product>(x => x.Products)
      .AsBag();
    Component<Address>(x => x.Address, m =>
    {
        m.Map(x => x.AddressLine1);
        m.Map(x => x.AddressLine2);
        m.Map(x => x.CityName);
        m.Map(x => x.CountryName);
    });
  }
}

Firstly, you’ll note that there is a marginal reduction in lines of code, but that’s not what we’re particularly striving for. Instead we’re intent on reducing the verbosity and noise of the code. This manifests itself in a convention over configuration design for the API, where we choose the most common setups and use those as the default. For example with the id element in the hbm file, you’re required to specify what the generator type is; however, in our fluent API we check the type of your identity property and decide what generator we should use. Int’s and longs default to identity, while GUIDs use the guid.comb generator. You can change these explicitly, but when you are using the default, it greatly reduces the verbosity of your mapping.

Testability

Another one of our goals is to make your mappings more robust. I imagine most people have had the problem where you’ve renamed a property and not updated the mapping file; due to there being no compile time validation, the only way to catch these mistakes are at run time (hopefully you had tests to cover that!). With the way our API is designed, you use the actual properties on your classes to create the mapping, so there’s nothing to forget. If you rename a property, your IDE will either rename the property in the mapping, or fail at compilation.

We also want to help you verify that your mappings are set up properly, not just syntactically valid. So to make your integration tests a bit easier, we’re providing an API for testing your mappings.

[Test]
public void VerifyCustomerSaves()
{
    new PersistenceSpecification<Customer>()
        .CheckProperty(x => x.Name, "James Gregory")
        .CheckProperty(x => x.Age, 22)
        .VerifyTheMappings();
}

Behind the scenes the PersistenceSpecification creates an instance of your entity, then populates it with the values you specify through the CheckProperty method. This entity is then saved to the database, then reloaded through a separate connection. The returned entity is then compared to the one originally saved, and any differences fail the test. It’s a fairly standard integration test, except we’ve taken the time to write all the wiring up that needs to be done, so you don’t have to.

The Framework

We’re working towards our first official release, which will have a fairly solid implementation of the API. Once that’s out in the wild, we’re going to focus on our Framework.

Our framework is a layer that sits on-top of the API to provide an even better experience. We’re looking to integrate with your favorite container, which will reduce the code you need to write to integrate NHibernate into your system. Then we’re going to tackle extensible conventions, which will allow you to specify your own implied conventions for your application. For example, if you’re always going to call your identifier “ID”, then why should you have to specify it every time? You shouldn’t!

Development is progressing at a nice pace, and I expect we’ll be able to get our first release out within the next few weeks. The testing API hasn’t been kept quite as up to date as the main API, but we’re working on that too. It’s open-source, so suggestions and patches are welcome.

17 comments ↓

#1 Justin on 08.08.08 at 7:38 pm

Really nice!
I’m curious how composite Ids work. If you’d just paste me a quick code sample I’d appreciate it.

#2 James Gregory on 08.08.08 at 7:48 pm

Unfortunately composite IDs currently aren’t implemented. I’ve created an issue for this and we’ll hopefully get to it soon.

Thanks for the feedback.

#3 Brian Johnston on 08.08.08 at 11:30 pm

An NHibernate I can get on board with. I’ve purposefully stayed clear thus far (for the most part) because the extra issues that you mention caused by an XML configuration file is more work than just using plain ADO.NET and code-snippets - even with relationships/mappings/etc.

I’m glad someone is recognizing that XML configuration files != better applications

#4 Mike on 08.10.08 at 3:44 am

I use object for my Id property and then define the generator to use in the mappings. is there a way to do something like this in the fluent interface like override the default reflection on the property type and force it to use Guid or something?

#5 Fluent NHibernate « Hendry Luk — Sheep in Fence on 08.10.08 at 10:41 am

[...] in Software Development tagged ORM at 10:41 am by hendryluk Jeremy Miller has done a great work on Fluent NHibernate (and here) that offers strong-typed nHibernate mapping configuration, requiring absolute ZERO xml! [...]

#6 James Gregory on 08.10.08 at 11:01 am

Mike: There is a workaround for situations like that. You can use Id(x => x.Id).SetGeneratorClass(”My Class Name”).

Care to describe why you have such a setup? It’s not something we’ve really considered.

#7 Mike on 08.10.08 at 9:44 pm

For a long time I have explicitly set the type on the Id, often passing in a generic TId for my domain superclass as is so common. (DomainObject)
In my latest project though I was refactoring to use Guid instead of int Ids and I wondered why I needed to define this explictly in my domain since I typically only use the Id for persistence and absolutely no business meaning.
All my persistence access uses object on any Id lookups anyways and I don’t think ( I could be wrong) that I am getting any boxing/unboxing penalties at runtime since NHibernate shouldn’t need to reflect on the class at all to assign the Id with the generator class defined.
It’s not a huge deal but it does seem to be more natural to have the persistence meaning in the persistence layer (NHib) .
So far I haven’t hit a single bump except perhaps a sloppy moment passing in a string representation of a Guid instead of a real Guid (from my ui layer)…but that just means my stupidity is revealed from a lower layer in my app.
I am open for any flaws in my thinking though. :)

#8 James Gregory on 08.10.08 at 9:51 pm

That’s an admirable goal, I’ve just never really seen it attempted before.

From my point of view, your domain is already compromised by having the ID in there, so having the type doesn’t make matters any worse, and it’s a bit easier for the developer. If it works for you though, that’s great.

Do you explicitly set the Id type in the mapping then? I imagine NHibernate wouldn’t be able to guess what the type should be.

#9 Mike on 08.10.08 at 10:09 pm

Actually, I do specify the type of the Id tag in an hbm.xml typically so there isn’t any guessing on NH’s part. I wasn’t so much trying to purify my domain as I was trying to minimize the amount of code touching I had to do if I change my Id strategy. I realize such an abrupt change shouldn’t happen with better planning but since I did it I havent’ heard a reason why not to just use plain ole ‘object’ for Id and let NH do the work for me.

#10 Willem Meints : Tired of using XML all the time? on 08.12.08 at 8:11 am

[...] soon get to at least 20 – 60 files. Alternatively you can make the configuration in code using Fluent NHibernate, which eliminates the need for XML configuration entirely. Note though that this doesn’t solve [...]

#11 W.Meints on 08.12.08 at 8:13 am

Great to see that it is possible to use NHibernate without having to write all those mapping files. It’s especially great since it prevents all those pesky runtime errors. Also users can’t mess up your application when you use this. I am aware of the embedded resource trick, but I don’t like that solution as much as this one.

#12 Grimace of Despair on 08.13.08 at 9:19 am

Last thing I read about using GUID’s for keys, is that it’s a bad idea, performance-wise, as they fuck up physical key clustering distribution, which at it’s turn, is essential to a performing database.

But I could be wrong :)

#13 Joe Ocampo on 08.18.08 at 6:58 am

Two words. “You rock!”

#14 Winston Fassett on 08.18.08 at 9:22 pm

Wondering why nobody mentioned using attributes for mapping, rather than XML. That’s what we do and it works out great and is pretty readable.

#15 James Gregory on 08.19.08 at 7:52 am

Winston: I’m not keen on the mapping attributes, because they pollute your domain model with persistence concerns. If they work for you though, that’s great.

#16 Praveen Angyan on 08.23.08 at 10:17 pm

One small concern. There’s a guideline for calling virtual methods in constructors. Basically don’t do it:

http://blogs.msdn.com/brada/archive/2004/08/12/213951.aspx

It’s too late in the morning for me to work through the implications of this, but Resharper threw this warning at me and doing a search uncovered the above guideline which Fluent NHibernate seems to violate.

#17 Robert on 09.25.08 at 1:10 pm

Constructors are executed bottom-up, so a virtual call could be implemented in a derived class before the constructor for that derived class has been executed. Its a point of caution, not a serious issue.

This is quite nice, but it still more verbose than NHibernate.Mapping.Attributes, or if commerical products are your thing then Diamond Binding (based on NHibernate) uses attributes are even cleaner and comes with a tool which syncs the class definition with your schema.

Leave a Comment