This email is about scenarios in which you need a separate persistence model in addition to your domain model.

I know, you have probably subscribed to this list because of my unit testing content, but I still receive questions about Domain-Driven Design (which I’ve spent several years writing about), and some of them are quite interesting. I’ll be posting the most interesting of those questions here too. Hope you don’t mind.

This article answers the question of whether you should map your domain classes to database tables directly using an ORM, or whether it’s better to use a separate set of Data Access Objects (DAOs) as intermediaries — a persistence model.

The persistence model helps keep the separation between the domain and database concerns. The use of an ORM (such as EF or NHibernate) often damages this separation of concerns because you can’t fully isolate your domain model from the influence of the database or said ORM. On the other hand, with a separate persistence model, you can keep the domain model clean more easily.

A typical solution with a persistence model looks like this:

DAOs usually have a 1-to-1 correspondence with the underlying database. The mapping between them and the DB is performed by an ORM; the mapping between the domain model and the persistence model is performed manually in repositories.

In the article, I argue that while a separate persistence model looks like a good idea, it leads to too much complexity in the long run.

Any non-trivial domain model will require you to invest a lot of time into building a respective persistence model, because you will have to re-implement a lion share of the functionality that ORMs already have.

Or you will have to cut corners and concede some domain model purity, in which case — what’s the point of building the persistence model in the first place?

My recommendation is to not have a separate persistence model.

You’ve already got a persistence model — it’s your database structure. Mapping between the domain model and the database is what an ORM does.

Even if your ORM doesn’t do a particularly good job keeping the domain model clean and separated from database concerns (I’m looking at you, Entity Framework), you are still better off using that ORM than writing your own.

Alright, that was a (rather long) recap of the article.

Although my position hasn’t changed, there are some scenarios where you do need a separate persistence model. In this email, I’d like to talk about such scenarios.

So, what are they?

#1: No ORM

Obviously, when you can’t use an ORM, you would have to map the domain model to the database manually. Of course, provided that you want to build a rich domain model and not just an anemic model that ties to the database as 1-to-1.

#2: Legacy application

You will also need a persistence model when you work on a legacy application, in which you don’t have control over the database structure.

That’s because legacy databases often have schemas that are impossible to map to a rich domain model using an ORM. They are too messy and complex. You just don’t have a choice other than to write your own mapper (i.e. a persistence model) between your clean domain model and the legacy mess.

The persistence model in a scenario with a legacy application is called an anti-corruption layer. Building an anti-corruption layer is a good technique for refactoring a legacy application.

I wrote a whole course on the topic of refactoring legacy applications. If you need a trial code that gives a 30 days unlimited access to Pluralsight, hit reply — I’ll send you one.

#3: Document databases

Finally, the third exception is document databases, such as MongoDB.

With document databases, you don’t need an ORM at all. An ORM stands for Object-relational mapper. Its main purpose is to bridge the gap between the object-oriented world (your domain model) and the relational world (your database). This gap is also known as object-relational impedance mismatch.

With document databases, you simply don’t have such a mismatch. Documents in document DBs are more flexible than rows in relational databases: a single document can store data of any shape and complexity. You don’t have to disassemble your classes into pieces (tables); instead, you can persist them as one blob (document).

With document databases, you also need a separate persistence model but for another reason. That reason is backward compatibility.

Let’s say that you have a User class with a Name property, which you decide to split into FirstName and LastName. With a relational database, you can write a migration script where you split this column into 2 for all existing users. The migration process itself is effectively instantaneous — just run the script and be done with it.

But you can’t write such a script with MongoDB because there’s no explicit structure — documents in the same collection (the User collection in our example) may all have different structure.

And so, to keep track of the different User versions, you need to introduce DAO classes like:

public class UserDaoV1
{
    public string Name { get; set; }
    public int Version => 1
}

public class UserDaoV2
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Version => 2
}

Such versioning will help you map these different versions to your User domain class.

You can also write a migration tool that would run at background and gradually migrate all users from V1 to V2, but again, that’s not an instantaneous process like with SQL migration scripts.

And so, you do need a persistence model (DAO classes) when working with MongoDB, but on the bright side, the mapping between the domain and persistence models is usually much simpler compared to relational databases. The reason is that you persist the whole aggregate in one document; you don’t need to "spread" it among multiple tables.

--Vlad


Enjoy this message? Here are more things you might like:

Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.

Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »

My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »