NHibernate: More on Top-Down, Objects First Development
“I'm thirty years old, but I read at the thirty-four-year-old level.” - Dana Carvey
Recently I participated in a Twittervation (“Twitter conversation”?) that started with a respected friend, who is a very well-known MVP, book author, and article writer, complaining that Entity Framework was a “pain in the ass”. That was “out of the blue”, it wasn’t in response to somebody else’s tweet.
Of course, I felt compelled to respond and tweeted, “NHibernate. Also PITA, but without all the MS data-centric baggage. (Just my 2 cents)”. Almost simultaneously, another MVP friend of mine who has a follower relationship with the first Tweeter and me said, “why not use NHibernate?”.
Subsequent Tweets revolved around “Don't get me wrong, not saying you shouldn't use it or that you're wrong for doing so. Just asking if you've seen NH”, and my ending with “I did a lot of research, man. It was painful. NHibernate won. End of story.”
Why did I say this?
I have no beef with LINQ To SQL. It works great, I’ve used it, and it is very easy to learn. I’ll continue to use it where appropriate. You can do data access with a greatly reduced number of lines of code. It’s kind of like Typed DataSets on steroids. With Entity Framework, you may have a steeper learning curve (especially since at this writing it is not 100% “baked”), but again the concept is sound.
So what’s the difference? Recently, Jeremy Miller, an MVP who can be attributed with the original impetus for Fluent.NHibernate, had an article published on MSDN, “Convention over Configuration”. Having an article like this accepted for publication at MSDN Magazine, Microsoft’s flagship developer publication, gives instant credibility to this paradigm, in my opinion. In other words, it’s going to “take off”. The basic concept is to be able to start with your POCO objects. “POCO” means “plain old CLR Object” – in sum, a class that describes a domain entity (e.g. “Customer”, “Product” --you get the idea) but without any “baggage” – e.g., no funky required attributes or decorations in order for it to “work”, no dependencies or required references to other assemblies, and so on. It stands on its own and it is PURE. I repeat – it really is pure! You can serialize it over the wire and it will be happy on both ends –- without you having to go through any programmatic contortions.
This isn’t a new concept to me – I wrote about “Contract First” back in 2005.
Next, you need conventions – which involves a series of “sensible defaults” that are built into the programming model. To the uninitiated, these could appear restrictive. But to the developer who understands “how” the programming model works, they provide a tremendous savings in time and efficiency. I’ll explain:
The key with NHibernate is that you can take these POCO’s (assuming they’re created with some sensible defaults) and ask NHibernate to map them. The NHibernate infrastructure will create “[POCOName].xbm.xml” mapping files that NHibernate can use to build the DDL SQL that creates your database schema. So you can create your domain model first –- the way it should be -- and from that, create the schema for the persistence mechanism. But, it gets better: The Fluent.NHibernate “Automapping” features mean that you can build this Infrastructure in memory via reflection without the need for any XML at all. The Automapping classes allow for “sensible defaults” that cover the majority of cases and still permit you to override these (perhaps your table names in the database are slightly different, or your primary key naming convention isn’t exactly the same, etc.) and allow you to get what you want. LINQ to SQL and Entity Framework become quite clumsy when you try to use them with this paradigm. And, unhappily, I believe it is unlikely they will change much going forward as they’re already kind of “baked” into Microsoft’s data-centric approach -- which really centers on having the database schema first, and the classes / entities coming from that.
The Fluent approach, which in a nutshell just means that every method returns an instance of the class, allows you to do much more intuitive programming along the concept of “DoThis().WithThat().ButAllowThis().Abracadabra(param) --- and so on. Should you need to make changes to your domain model (which is often the case during development) you can run the automapping again to keep your persistence schema right in sync.
James Gregory (one of the active contributors to the Fluent.NHibernate project) has a wonderful set of blog posts that really bring this home. I hope you’ll read them, as well as the Google Group for same, which is starting to attract a nice following and some great contributions that are sure to make you “think outside the box”. I’m having fun with Fluent.NHibernate. As with any learning curve, it may be somewhat painful at first. But you know what? I got religion on this, man. It works! Take the time, and it can work for you to. You’ll thank me later.