I decided to post some things which I had to overcome in order to be an effective user of NHibernate before I forgot. My first post dealt with the first fundamental paradigm shift which I needed to grasp which was the difference between Data-Centric and Object-Centric Domain modeling. I noted that the line between them isn't always 'cut and dry' but that's the best way I can express the difference between approaching business solutions with a data model in mind vs. solving business needs with a rich object model that assumes that mapping to persistence can happen.
This assumption, though, might be an erroneous one if you choose an Object Relational Mapping (OR/M) tool that doesn't support the richness your domain demands. That's why looking back I am glad that I chose to dive into the NHibernate camp. Not that there are not other good tools out there, but I have thrown some complex requirements at it and have found it more than able to meet my business need instead of the other way around. But I did at least try other tools first and the next paradigm shift in my mind that began forming had to deal with how I perceived persistence of objects:
INHERITANCE STRATEGIES FOR PERSISTING OBJECTS TO A DATABASE (OR OTHER STORE)
Coming out of the purely data-centric fog of Microsoft documentation left me appalled when I discovered how Very Important People like Martin Fowler proposed to persist objects to a database. Being convinced that the Holy Grail is Database normalization, it is understandable why I considered dropping anything to do with OR/M solutions that proposed that an entire inheritance hierarchy be represented in a single table. "But that means some of my columns will be NULL and that is bad relational modeling." That's what I'd read everywhere and then along comes OR/M and says..."Yeah that's what that means...so what".
This dilemma emerged first because of confusion about duplication and redundancy. I'd read that one of the driving benefits and goals of Object-Oriented Principles (OOP) was to reduce duplication of code and promote reuse. Basically, I didn't understand the notion of Value Objects versus Entities from the Domain-Driven Design (DDD) camp and so thought All Things in my database should never be reference by their values, but rather by their surrogate key. The notion of Aggregate objects was foreign to me and so I'd spend brutal hours trying to be a database designer while sweating because I was going to have to write and maintain the data access code to stick this in my 'objects'. For example, if I had a Contact object that needed to have an Address, I only saw strict rules about having the same Address only listed once in a table(s) because that would be representative of the 'real world'...only one place can be, well, in a place at a time right? While that may be suitable for scenarios, there are times when that simply is not necessary and can be a Pandora's box to attempt to preserve the uniqueness across all of the domain. The big difference is this...I was making my decision not based on what the business rules and needs stated but by what I thought the technology should look like (ie, beautiful table structure).
All of that is to say that the impedance mismatch was something I was just beginning to unearth and my first hurdle was Inheritance. Now, my Design toolbox was (and I think still is) quite empty...the hammer called Inheritance was beloved to me and my elegant Stored Procedures nurtured the affair I had with it. When I downloaded Paul Wilson's ORMapper I was startled to find that subclassing while preserving normalization was not the Holy Grail. In fact, the samples had Phones and Addresses in the same table. WHAT!?! How dare he?! "Aren't these supposed to be logically separated into different tables?"!
There were a few key things I needed to learn and grow up in:
There are different ways to represent inheritance in a database
See NHibernate's documentation for a good description of them. You can ignore the NHibernate specifics and still get a grasp of the strategies. I think it is important to have a tool that at least supports these strategies for mid- to large- size applications. Smaller applications may not require this sophistication. Also see Martin Fowler's PoEAA book...a catalog of patterns (brief) is here.
Inheritance is not always the answer to extending an object's behaviour or use
In fact, when applying Domain Driven Design principles it seems to be an intention and not an assumption. Instead of knee-jerking your design into inheritance just because some methods or properties are shared between objects, look deeper into your model and see if Aggregation or Composition don't suit your intentions better. Without noticing, I have found that subclassing to me is much rarer than when I first began. I discovered that some OR/M tools do not support inheritance across multiple tables (Joined-Subclass strategy) but now I realize that THIS MAY NOT BE A BIG DEAL. For larger apps I definitely think that should be a feature, but not all apps are that sophisticated. There is much more to say on this topic, but the point here is simply that inheritance is not always the answer and so a simple data mapping solution might be feasable.
Normalization might be prettier, But...
if you are going to be a stickler on performance representing a whole Inheritance Hierarchy in the same table might be faster, according to people smarter than me.
The "Stored Procedures are the only way to be secure" notion is a myth.
'Nuff said.
Resources: