Fluent NHibernate and those sweet LINQ repositories
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...
Comments
-
Wicked Cool! Hey, I noticed the “ShouldEqual”, where’d that guy come from?
-
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!
-
Hey, how invasive of a tool is Fluent NHibernate? I don’t like anything bulky or in my way when I’m coding,
-
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…