There are three patterns in common use that deal with mapping object inheritance to relational databases. We didn’t discuss any of them in my graduate databases course (sigh), and our friend ActiveRecord implements only one of them: Single Table Inheritance (STI).
STI is what you use when you want to represent an object hierarchy by mapping the union of all attributes found in that class hierarchy to a single underlying database table. Yup, it’s a mouthful. And it works great if the attributes available on the subclasses all tend to be very similar. It’s very fast (comparatively), but makes poor use of space since unused fields are just left null. ActiveRecord’s implementation uses a type field in the database to identify the subclass that the row belongs to.
So what about alternative approaches? There are a couple…
First up is Concrete Table Inheritance, in which there are n database tables for n concrete classes in the hierarchy. Although I’m sure there are cases where this must be useful, I can’t think of a single one. The problem is the silly amount of replication that happens here — fields common to classes will get replicated across tables. This means a lot of replication, more and more as the object hierarchy gets deeper, and a lot of difficulty when it gets to be refactoring time. Bleh, no thanks.
Class Table Inheritance, by contrast, has a table for each class, including interior nodes in the hierarchy (classes that have derivations). A subclass is represented at the database layer as a table that has some number of additive fields plus a foreign key to it’s parent class, which contains the fields that are common to all ancestors.
Conceptually, this seems like the cleanest strategy to me, and the most “OO” of the approaches. However, when we think about the implementation, we realize that performance is going to be a big issue: the class-table strategy is going to require n joins for an object nested n levels into a class hierarchy. Ouch.
Despite that admittedly ugly problem, there has been some interest in implementing Class Table Inheritance in ActiveRecord. In fact there’s some contributed code on the Rails wiki that should allow you to use it as an alternative to STI in Rails. Someone should plugin-ize it, perhaps.
I initially set out to look at alternative DB/object mappings because I was frustrated by the fact that STI wasn’t “accommodating” enough for me. At one point I thought that Class Table Inheritance might be a better match for a specific problem we were looking to solve. It turns out that wasn’t really the case at all; The problem wasn’t STI, it was the way our object hierarchy was structured.
My Lesson Of The Day for February 16th, 2007: If your object hierarchy is relatively shallow, and the single table strategy produces ugly results for you (lots of null fields on subclasses), take another look at the relationships between your objects. STI is a great fit for things that are very closely related to the parent class and require few extra attributes to express that. It’s a lousy fit, otoh, for object relations that aren’t tight like rockstar pants. If both CarPart and DogLeash share the parent class Purchase, they’re probably not good candidates for STI (wink, wink).
Embarrassed as I am to admit it, that was sort of the problem. More on that later, maybe.