Fluent NHibernate and those sweet LINQ repositories

written by tobinharris on August 9th, 2008 @ 09:12 PM

Fluent NHibernate is a tool that lets you easily write NHibernate mappings.

I downloaded the code and was awe-struck. It's really tidy and full of nicely implemented ideas.

In-Memory Repository

One of them was the in-memory repository class. It uses LINQ for queries, and keeps an in-memory cache of objects. Check out this test-cases that demonstrates it's use.

        InMemoryRepository repository = new InMemoryRepository();

        repository.Save(new Case { Name = "Jeremy", Number = 10 });
        repository.Save(new Case { Name = "Darth Vader", Number = 5 });
        repository.Save(new Case { Name = "Darth Maul", Number = 6 });
        repository.Save(new Case { Name = "Luke", Number = 12 });
        repository.Save(new Case { Name = "Han Solo", Number = 6 });
        repository.Save(new Case { Name = "Eric", Number = 5 });
        repository.Save(new Case { Name = "Corwin", Number = 4 });

        repository.FindBy<Case>(c => c.Name == "Corwin").Name.ShouldEqual("Corwin");
        repository.FindBy<Case>(c => c.Number == 10).Name.ShouldEqual("Jeremy");
        repository.FindBy<Case>(c => c.Number == 6 && c.Name == "Han Solo").Name.ShouldEqual("Han Solo");

Gotta love the Star-Wars geekery :)

This kind of repository is useful for testing domain logic without hitting the DB. This in turns makes domain model testing very fast. For example, the 263 in-memory test take only 4 seconds to complete. I could live with that.

LINQ for NHIbernate Repository

Jeremy has also created a real repository that implements the same interface as the in-memory one. That means it also uses LINQ. And that means it uses LINQ for NHIbernate - hurrah !

Here's the real repository in action:

        ISession session = _source.CreateSession();

        session.SaveOrUpdate(new Record { Name = "Jeremy", Age = 34 });
        session.SaveOrUpdate(new Record { Name = "Jeremy", Age = 35 });
        session.SaveOrUpdate(new Record { Name = "Jessica", Age = 29 });
        session.SaveOrUpdate(new Record { Name = "Natalie", Age = 25 });
        session.SaveOrUpdate(new Record { Name = "Hank", Age = 29 });
        session.SaveOrUpdate(new Record { Name = "Darrell", Age = 34 });
        session.SaveOrUpdate(new Record { Name = "Bill", Age = 34 });
        session.SaveOrUpdate(new Record { Name = "Tim", Age = 35 });
        session.SaveOrUpdate(new Record { Name = "Greg", Age = 36 });

        Repository repository = new Repository(_source.CreateSession());
        Record record = repository.FindBy<Record>(r => r.Age == 34 && r.Name == "Jeremy");
        record.Name.ShouldEqual("Jeremy");
        record.Age.ShouldEqual(34);

There are currently only 9 integration tests that actually use NHIbernate and hit a DB. Pretty cool considering the nature of the project.

Lots to Learn

There's a lot to learn from this project.

One thing is that not hitting a database for 90% of your tests is a GREAT THING.

In this project, the 9 tests that hit the database take a whopping 7 seconds to run on my machine! That's 0.8 seconds per test on average. The in-memory tests take only 0.015 seconds each on average.

Favourite Mapping Technique?

I have a feeling that Fluent-NHibernate will become my favourite way of writing mappings for NHIbernate. And, I soon hope that it will soon be my favourite way of NOT writing mappings for NHibernate :) Of course, they'll need to get their Auto Mapping working for that, but I believe they'll do it within the next 2-3 months.

I now looking forward to browsing more of the code and trying out the tool...



kick it on DotNetKicks.com



Comments

  • Chris on 10 Aug 02:22

    Wicked Cool! Hey, I noticed the “ShouldEqual”, where’d that guy come from?

  • Tobin Harris on 10 Aug 15:26

    Yeah, it’s a nice touch! They’re written a bunch of extension methods that give “object” for a more fluent testing protocol. These call NUnit methods behind the scenes. Example:

    public static class SpecificationExtensions
    {
        public static void ShouldBeFalse(this bool condition)
        {
            Assert.IsFalse(condition);
        }
    }
    public static void ShouldBeTrue(this bool condition)
    {
        Assert.IsTrue(condition);
    }
    public static object ShouldEqual(this object actual, object expected)
    {
        Assert.AreEqual(expected, actual);
        return expected;
    }

    Clever stuff!

  • Sara on 10 Aug 20:15

    Hey, how invasive of a tool is Fluent NHibernate? I don’t like anything bulky or in my way when I’m coding,

  • Tobin Harris on 11 Aug 03:47

    Hmmm, good question. I can’t honestly answer that, because I’ve not got into the nitty gritty of Fluent NHibernate.

    The way for setting up NHIbernate mappings looks quite light – see here

    I’m pretty sure that the library is fairly loosely coupled which helps it play nicely with other things without jumping through hoops (thus non-invasive).

    For example, I think I can use it with the Rhino stuff without complication (just pass the UnitOfWork.CurrentSession into the Fluent-NH Repository and you’re off…)

    But, not tried it yet, so I may have to answer this question after some more investigations…

Post a comment

Options:

Size

Colors