Why Avoid Using ORM with Domain-Driven Design?

%fdomain-driven-design

I've just finished reading Scott Wlaschin's excellent book "Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#" in which he uses the F# SQL type provider for the database access.

Anticipating the obvious question, he says (p260) not to use an ORM because you can't ensure the integrity of the domain that way. For example, an ORM can't validate an email address, etc, can't deal with nested choice types, etc.

However, earlier on in the book (can't find it offhand, so I hope I quote him correctly), when explaining how to create boundaries for each section of the workflow, he says that data should be validated at each section boundary, allowing the code within the section to assume it's all valid.

If so, why not treat the entities coming out of the ORM and into your code as crossing a boundary, and validate them there? That way, you get the benefits of the ORM, but ensure the integrity of your model.

Best Answer

To be clear, I said "In F#, we tend not to use an object-relational mapper (ORM)" but not because of any validation issues, rather because a big ORM like Entity Framework is heavily object-oriented (surprise!) which doesn't always mesh well with a functional paradigm. Instead F#ers will either use type providers or a simpler library such as Dapper.

In the "Working with Relational Databases" chapter, I do say that you can treat the database in two different ways:

  • as a untrusted source, in which case you do validation in the usual way (just as you would for data coming from a JSON Web API, say)
  • as a trusted source, in which case you don't do validation and throw exceptions if the data is bad.

Which case applies depends on whether the database is shared with other applications, how it is designed, etc.

Update: I realize that the following sentence could be misinterpreted:

Can’t we just use something like Entity Framework or NHibernate that will do all this mapping automatically? The answer is no, not if you want to ensure the integrity of your domain.

What I meant by that is that translating a domain model directly to a database via an ORM means that you lose a lot of the complexity of the domain types -- the "make illegal states unrepresentable" design approach that I dedicate a chapter to. This is because ORMs don't know how to handle single-case unions with constraints, complex choice types, etc.

Instead, I recommend that you translate your domain objects to a type specially designed for persistence (a "DTO") and then use that DTO for persistence, not the domain type. To store/load the DTO you can certainly use EF or NHibernate, but you're not getting much value from it when you use it that way, and so it's generally easier to use type providers or a lightweight mapper like Dapper.

Related Topic