Having the domain model separated from the persistence model



In this post, I’d like to write about a pretty common discussion in DDD circles: should one have the domain model separated from the persistence model? In other words, should you map your domain objects to the DB tables directly using an ORM or would it be better to use a separate set of Data Access Objects (DAOs) instead?

Should a domain model serve as a persistence model?

This question often arises when you try to build a rich domain model while working with a relational data store. To answer it, let’s first look at why one would even consider creating a separate set of DAOs.

It’s true that building a rich domain model that adheres to the DDD principles is not an easy task. To make your code base maintainable in the long term, you need to have it separated from all responsibilities other than holding the domain knowledge. It means that all persistence concerns must be extracted out of the domain classes.

At the same time, the use of ORMs might damage this separation as they impose limitations on how you design the domain model. Some sophisticated design techniques may be hard to implement when an ORM chimes in.

Creation of separate DAO classes is one of the solutions to this problem. With them, it is easier to keep the domain model pure. A typical solution with a persistence model involved looks like this:

A typical solution with a persistence model

A typical solution with a persistence model

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

So having that said, should you create such a persistence model in order to build a rich and isolated domain model? The quick answer is: no, you don’t have to. Now let’s see why it is so.

A common belief here is that if your application is not too complex, you can trade some purity for the speed of development, and just have your ORM of choice map the domain objects directly to the database. Not a pretty solution, but it works and doesn’t take much time to implement. On the other hand, if you are willing to invest in your code base, you can put in some effort and extract a separate persistence model in order to keep the domain clean.

This belief can be diagrammed as follows:

Building your own persistence model: the common belief

Building your own persistence model: the common belief

As the diagram shows, the more work you put, the better results you will have.

In reality, however, it is not the case. The outcome doesn’t grow linearly with the amount of effort you put into implementing your own persistence model. At first, you may have some impressive results as you are able to pretty quickly set up basic mappings between your domain and persistence models.

For example, it’s quite easy to map a single entity to a single table, even if that entity contains lots of Value Objects. However, the further you go into it, the more difficult the task becomes.

One-to-many relationships between domain classes (when a class contains a collection of domain objects) aren’t as easy, especially if you want to somehow distinguish between changed and unchanged objects in the collection. Many-to-many relationships (when both classes have collections of references to each other) are even more difficult to map. Heck, even a single reference from one class to another can pose serious problems.

Eventually, you have a choice to either re-implement a fair share of the functionality ORMs already have or give up on the ideal purity and start to cut corners. And I never saw anyone choosing the first option. In the reality, the amount of work needed to implement a pure domain model with a separate persistence model looks like this:

Building your own persistence model: the real state of affairs

Building your own persistence model: the real state of affairs

The real amount of work to rich a complete purity is always more substantial than we perceive it. At the same time, with a partial persistence model, we just trade one sort of purity for another, netting to zero or even a loss comparing to the approach without such a model.

Why? Mainly because ORMs already do a lot of work for you. For example, with your own persistence model, you are not able to benefit from the built-in change tracking functionality. And that means you will not be able to implement reliable domain events – the ones which get fired only when a transaction gets committed to the database. You either need to build a change tracker yourself or give up on such implementation of domain events.

Why is the approach with a separate Persistence Model popular?

It’s interesting to discuss why the approach with a separate persistence model has become so popular. Aside from the point I made earlier regarding underestimating its complexity, I think there are two reasons for that.

First of all, in large organizations, it is still quite common to have a team of developers who work on an application code base separately from a DBA team which manages the underlying database. In this situation, the application code base usually evolves in a much faster pace than the database structure. And it becomes too difficult to manage the mapping between them with an ORM alone. Introduction of a persistence model is inevitable in this case if you want to have a more or less isolated domain model.

However, such situation is a sign of a bigger problem. The problem here is that the application’s database shouldn’t be treated separately from the “regular” code base and must evolve with that code base hand-by-hand. To make it work, the application and its database should be managed by a single team. Check out this article if you want to learn more on how to do that.

The second reason is Entity Framework. Because of the support from Microsoft, this ORM has become the default choice for many (probably most) of the .NET developers nowadays. This is a disappointing trend because, in spite of being developed for many years, it still has major shortcomings in terms of purity. These shortcomings push the developers who seek better isolation for their domain models towards custom persistence model implementations.

If you are one of such developers, just switch to NHibernate. Really. This ORM has everything EF has (except for async DB operations) and much more. You won’t even have to re-learn too much because all modern ORMs are very similar to each other and your experience with EF will be very well applicable to NH (and vise versa).

I’ve been working with both of them for many years and I would say that Entity Framework is still not even close to NHibernate in terms of domain model isolation. Sure, you will still have to change your domain model in order to work with NHibernate but the impact of those changes is minuscule comparing to the benefits you’ll get out of it. Here’s the full list of such changes:

  • You’ll need to mark all non-private methods and properties as virtual in your entities (but not in value objects).
  • You will not be able to mark your entities as sealed (you will be able to do that with value objects, however).
  • You will need to introduce a parameter-less constructor for entities and value objects (which can be made private or protected).
  • You will have to be cautious when you deal with the GetType method. For entities, it returns the type of an NHibernate’s runtime proxy instead of the entity itself.

They aren’t pleasant but only the last change actually mean a leakage of an ORM concern to the domain model. Encapsulation of your domain classes is not violated at all.

All DDD practices can be implemented with NHibernate directly, without involving a separate persistence model. And it scales. With NHibernate, it is possible to build large systems whose domain model is easy to understand, unit test and refactor. For an example of a project that uses NHibernate, you can watch my DDD in Practice course on Pluralsight or just examine the source code of the sample project on Github.

Overall, the Complexity/Purity diagram looks more like this:

With vs without own persistence model

With vs without own persistence model

Conclusions

A fully-fledged persistence model is too costly to implement, whereas with a partial one, you merely trade one kind of purity for another with an additional cost of building and maintaining your own mapping.

NHibernate provides the best set of trade-offs between the implementation complexity and the overall purity. There still will be ORM concerns leaking into your domain model, however. But I think it’s a low price for all the benefits you’ll get out of it: speed of development, rich functionality, and separation of concerns.

Related articles:

Share




  • youzer

    I can’t help but treat my persistence layer as an anti-corruption layer.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      It is an anti-corruption layer. The point, however, is that ORM itself is also such a layer, and it comes at a much lower maintainability cost.

  • Flynn

    Very interesting post. Thanks a lot.

  • Alexander Yevseyev

    Unfortunately many developers look only on benchmarks where usually NHibernate loses to EF dramatically. People are saying that NHibernate is slower in it’s queries and object creation and they are right, but forget it’s best features you keep mentioning. Maybe you’ll get throught to sombody with it.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Last time I checked, NHibernate produced more performant SQL comparing to EF. This could have changed since then, though.

      • Alexander Yevseyev

        Could you, please, share a link or test code? Maybe I’m out of date.

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          I can’t come up with a quick example right now, but I’ll try to do some research on this in the future. It’s been a long time since I looked at it last time.

  • Guillaume L

    Great post, I couldn’t agree more.

    Since people came up with this concept of “persistence model” a few years ago, I always felt it was an oxymoron. You’ve already got a persistence model – it’s your database structure. Mapping between the object model and the database is not another model, it’s an action. That’s what an ORM does. You configure it to do so by specifying the steps it must take to map from one realm to the other.

    Just because some object relational mappers (especially Entity Framework) do a poor job of fullfilling basic ORM requirements doesn’t make this umpteenth layer of abstraction in your app a meaningful concept. “Persistence Model” is a misnomer, it should really be named Repair patch for lousy ORMs Model.

  • Maxim Balaganskiy

    EF Core is pretty good with the isolation. I would vote against categorical statements such as “NHibernate provides the best set of trade-offs”. Even with EF6 you could use pure POCOs.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      EF Core is doing better in this regard but still is lagging behind NH.

      Even with EF6 you could use pure POCOs.

      When comparing EF and NH, I write about EF Code-First only, I don’t take into account the DB-first approach which is much worse in terms of separation of concerns.

  • http://sidburn.github.io/ David Raab

    I also like this post, but (it seems i always have something to complain about, sorry, i don’t mean it negative) for me what you describe has less todo with your question you started.

    Keeping the domain model separate from the persistence model is something that you also do with your NHibernate approach. Keeping it separate doesn’t mean you automatically write your own DOA objects to do the mapping. Picking an ORM that does it for you is still separating.

    Not keeping it separate is more a case for those “Active Records” ORMs. That directly adds “Insert, Update, Delete” methods to the objects itself. Or basically creating such classes yourself with all the Database handling inside the class itself, instead of separating it.

    Keeping it separate doesn’t mean you must write it yourself. You can keep it separate with an ORM or writing it an ORM yourself. The same is true the other way around. You can include the persistence model in the domain model with an ORM and also writing it yourself.

    The question is basically more, do you write your own ORM or do you just use a existing one. And i don’t think that rewriting it yourself gives someone much benefits, like you explained in your post.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good points regarding where a persistence model can reside. By “Persistence Model” I meant specifically the one you write to mimic the database structure, the DAO classes. That is, afaik, a common usage of that term.

  • Hristo Yankov

    When you realize that the database is an extension of your code (i.e. with the “code first” approach) and is de-facto an implementation detail, instead of a separate pillar around which you wrap your application… then it makes perfect sense to use EF and map your Domain Models to the database. EF provides enough abstraction and there is really no need to introduce another layer – the “persistence model”.

    Let’s say you decide to use a relation database, ok? This is a core architectural decision and will not change. What good is exactly doing the persistence model for you?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Is it a rhetorical question? Because I believe your thoughts concur with the points from the article 🙂

  • Joseph Anthony

    Still not sold. We have always kept our domain model free of persistence, but were not bothered by writing a Data Access Layer that pointed to stored procedures. This work is not hard, it is not what slows down a project, it is not what has been the source of errors, etc. Teaching new developers how to use NHIbernate or any other other entity persistence framework is not needed. Seems every couple of years it gets investigated again but never builds up enough momentum on the team to get used. I assume somewhere some goofballs are trying to write their own magical data table object linking layer, all over-complicated and messy, instead of using a prepackaged solution. For them an entity framework is great, for those who don’t feel the need for the magic, a service that calls stored procedures seems to work fine and is simple enough to hand over to any person who knows the language.