Somewhere in the middle of 2004, I decided that I needed to take a look at additional ways to deal with persistence, beyond store procedures and code generation using Code Smith. At the time, I was mystified by the all the noise around ORM, business objects, and domain-driven design. I had data sets and stored procedures, and I had code generation to make working with them a bit easier, and the world was good. But as I began to deal with more complex applications and attempted to learn from the collective knowledge in the community, I began to see the problems with this approach.
Eventually, I understood the significant problem with my previous method of working with data: I was building procedural applications, where the data was king and the application behavior was, at best, a distant second. This approach doesn’t scale well with the complexity of the applications we need to build. Indeed, this programmatic approach has been largely superseded by object-oriented approaches. I see no reason that this shouldn’t apply to dealing with data as well.
I can no longer recall what made me decide to focus on NHibernate—it was probably an enthusiastic blog post, come to think of it. But whatever the reason, I made that choice. Four years later, I have yet to regret this decision, and I am proud to state that exactly 100 percent of my projects since then have used NHibernate for persistence. That decision has paid off in many ways.
Two occasions come to mind in particular. The first was a very ... tense meeting with a client, where the client DBA was furious about the need to support SQL Server. That was the client’s requirement, but the DBA saw it as an encroachment on his territory, and he didn’t like it one bit. In his eyes, DB2 on AS/400 was what the client had used for the last eon or so, and it should be what they used for the next eon or so. During that meeting, I pulled out my laptop, found the ADO.NET provider for DB2, and configured the application to run against it. I asked the DBA for the credentials of the test database and had the application running against it within 45 minutes. We ended up going for production on SQL Server, but that was the client’s choice, not an implementation imperative.
On the second occasion, we had to build a fairly complex multi-tenant HR application on top of a legacy database that was imported from a mainframe and was enough to make a person cry. The table names were numeric (of course, table 200 is the employees table) and were different from one tenant to the next, and the database model was a direct copy of the flat files used in batch processing on the mainframe. Trying to build an application on top of that (and it couldn’t be changed) would have been challenging, to say the least. We were able to build a domain model that was mostly free of all the nonsense in the DB layer and map from the DB to the domain model for each tenant. I wouldn’t call it simple by any means, but we were able to encapsulate the complexity into a set of mapping files that were maintained by the system integrators (who were the only people who understood what value went where).
In both cases, I managed to get tremendous value out of NHibernate. In the first case, it provided a good reputation and the ability to remove hurdles in working with the client; in the second case, we made the problem simpler by an order of magnitude if not more. The team worked mostly on the UI and the business problems, not on solving persistence issues.
I’ve been using NHibernate since version 0.4 or 0.5, and I have watched (and had the honor of taking part in) how it has grown from a simple port of Hibernate on Java to have a personality, community, and presence of its own. NHibernate 1.0 gave us parity with Hibernate 2.1, with support for common scenarios, but it was still mostly a port of the Java version. Starting with 1.2, we’ve seen more and more work being done not only to make NHibernate more friendly to the .Net ecosystem, but also to add features that are unique for NHibernate.
NHibernate 1.0 was a good ORM for the time, looking back at it, but it seems bare-bones compared to the options that we have now with 1.2 and 2.0.
NHibernate 1.2 added support for generics, stored procedures, multiqueries, write batching, and much more. NHibernate 2.0 is focused on parity with Hibernate 3.2, with events and listeners, stateless sessions, joined and unioned classes, detached queries, and much more. On the horizon is a Linq provider for NHibernate, which is being used in production by several projects and will likely be released as part of NHibernate 2.1.
NHibernate is also able to benefit from the ecosystem that grew around Hibernate, and ports of Hibernate’s satellite projects exist for NHibernate. I’ll mention NHibernate Search, which lets you integrate your entities with the Lucene.NET search engine; and NHibernate Validator, which gives you a powerful validation framework. NHibernate Contrib contains more examples. But the extensions available for NHibernate go beyond ports of Java projects. Rhino Security is a project that gives you a complete business-level security package on top of the NHibernate domain model, and it uses NHibernate itself to do that. Several projects provide mapping by convention to NHibernate, and a big community of users are sharing knowledge and issues on a daily basis.
This rich ecosystem didn’t happen by accident, it happened because NHibernate is a flexible and adaptable framework; and when you come to understand the way it works and how to utilize its strengths, it will bring significant benefits to your projects. But being flexible and adaptable comes at a cost. Many people find that NHibernate has a steep learning curve. I disagree; but as one of the committers for the project, I’m probably not a good person to judge that particular aspect of NHibernate.
When I started with NHibernate, I got Hibernate in Action (Christian Bauer and Gavin King; Manning, 2004) and read it from cover to cover. My goal wasn’t to memorize the API; my intent was to understand NHibernate—not just the API and how to use it in simple scenarios, but also the design approach and how NHibernate handles issues. To my joy, Hibernate in Action contained exactly that kind of information and has been of tremendous value in understanding and using NHibernate.
But Hibernate in Action is a Java book, which is why I was happy to hear (and read) about this book. NHibernate in Action is not simply a reproduction of Hibernate in Action with different naming conventions. This book has accomplished the task of translating the knowledge and of adapting and extending it. I consider this book to be essential for any developer who wants to be able to do more than the basics with NHibernate. And it certainly helps that the book covers NHibernate-specific features, which do not exist in the Hibernate version.
OREN EINI, A.K.A. AYENDE RAHIEN