I realized the other day that it’s been nearly two years since I wrote a series of posts as I was learning to use NHibernate for data access. I haven’t really blogged a whole lot about NHibernate (I leave that to our resident expert, Chris) but I’ve certainly been working with it a bit. And I’ve learned to like it a lot.
A little background on what I’ve been doing – the recipe tracker app I was using as a sort of “hello world” has increased greatly in scope (good thing that never happens in our day jobs, right 😉 ). It has gone from a desktop app to a slightly better desktop app before reaching its current state as a web application. In the process it has also gone from using an embedded database for the back end to a full blown RDBMS. The only thing that’s remained constant is the data access code, and I think that’s kind of beautiful.
I thought it may be worth writing down some of the things I’ve learned in the process so that I don’t forget them later. Most items discussed probably apply to any ORM but, since my experience is specific to NHibernate, I will keep things focused there.
The Domain is Everything
Seriously. More than a few times, I found myself in a situation where I was banging my head against the wall, wondering why the hell anyone would ever use NHibernate. And each time, when I calmed down a bit, I realized there was a flaw in the way my domain was modeled that was the root cause of my troubles. It’s a pretty general lesson, but I think it’s important to note. NHibernate can save you a lot of pain, but for the most part it isn’t magic. If you have a poorly conceived set of domain objects, I don’t think any ORM is going to help you until issues in the domain are taken care of.
Sometimes it is Magic
The ease with which NHibernate lets you enable lazy loading and plug in second level cache providers is truly awesome. I know it’s really the product of a lot of hard work, but to me it sure seems like magic!
You Can’t Forget SQL
I’m not sure forgetting SQL was ever the point, but every once in a while I read something that seems to suggest this. If you decide that you can forget all about SQL because you’re using an ORM, you will suffer :> (and not just because the DBA will come after you). When I’m debugging I constantly keep an eye on the SQL generated by NHibernate – if I see something that looks off, there is usually something in the mappings that needs to be corrected. Some things, like phantom updates can be detected with just a bit of common sense, but others can be a bit trickier. If you’re using a relational database in your system, forget the language it uses at your own peril.
Minimize Session Creation
You can probably file this under things a noob should know about NHibernate before even getting started, but as I was getting started I was blissfully unaware of the cost of creating sessions. Luckily I was just creating WAY TOO MANY sessions and not leaking them. But it still got pretty costly, and it also makes NHibernate’s first level cache almost useless.
Write Integration Tests!
This is probably THE most important lesson. I’ve switched databases four times now (SSCE -> SQLite -> SQL Server -> MySQL -> Postgres) and I’ve almost got it down to a science for my particular application. Database portability was one of my goals when starting the project, and living through a huge project for database conversion at work in 2008-09 has greatly increased my appreciation for this goal. But you’ve gotta remember that NHibernate only makes it possible. It’s a nice set of integration tests that prove your persistence layer is still doing all the things you expect that makes it work.
It’s Not for Everything
The list is getting smaller by the day, but there are some use cases where I imagine an ORM wouldn’t be the best fit. For situations where you need the absolute best performance you can get, maybe abstractions designed to help with maintainability and developer productivity are a luxury you can’t afford. I suppose if you had a system facing an absolute deluge of incoming data (trading applications and systems collecting data from machinery come to mind) this could be the case, though I think a message queue would help much more in these kind of scenarios than any particular data access strategy.
If I think of anything I missed I’ll try to come back and edit this post. These are what came to mind at the moment, but who knows what tomorrow will bring.