Yesterday, the wolf pack was talking through a particularly complex domain model. It was much more complex than your general one-to-many, one-to-one issues; it contained objects that were very fluidly related and often cross-related. Object A has a collection of Object B, except sometimes Object B is a child object of Object C in Object A’s other collection. Object B is also the parent of Object D, which may or may not be associated with an Object A. So on, and so forth.
Of course, this wasn’t a discussion about coding; this was a discussion about how our customers wanted to use the software and what kinds of interactions best fit how they wanted to use the system.
So, we got a basic model put together that seemed to be all right, and just for kicks, I let Entity Framework generate the database tables. It did a great job, making decisions about keys and constraints and who owned what relationships that I probably would not have thought of. It was pretty genius. But here’s the catch: although the object model made sense, using that database table structure – ingenious as it was – would cause lots of multiple table joins for even some of the most basic things users would want to see and do.
Then, the conversation moved toward the most efficient relational database design to get the performance we wanted, knowing we could use the ORM to map our objects to whatever structure we came up with.
A lot of times, when people think of ORMs, the main value they think of is not having to write a lot of data access code. This is certainly an important value, and I don’t want to minimize that, but that’s sort of like saying the primary value of TDD is the ability to refactor your code without breaking anything. It’s certainly important, but not really where most of the bang for your buck comes in.
To me, the real value of the ORM is the decoupling of your database tables from your object model. This allows me to write my domain in the way that best reflects how these things actually interact in our business, in our code, and for our customers – while at the same time being free to optimize the database for the most performant way to store and retrieve the data relationally. Having the extra layer of abstraction also allows me to tinker with either layer without breaking anything.
For simple applications, your database tables and domain classes may look similar, and for applications using NoSQL, this issue is barely on the radar if at all, but for complex apps using relational databases, you really don’t want your domain looking like a bunch of database tables and vice-versa. Those two things have completely different roles in your application and have very different definitions of efficiency and good design.
So, if you struggle with your domain being hard to model in a database, or your domain is full of classes like “UserToRoles,” you might look into whether or not an ORM would help you out.