7

A lot of tutorials on DDD I studied are mostly covering theory. They all have rudimentary code examples (Pluralsight and similar).

On the web there are also attempts by a few people to create tutorials covering DDD with EF. If you begin studying them just briefly - you quickly notice they differ a lot from one another. Some people recommend to keep the app minimal and to avoid introducing additional layers e.g. repository on top of EF, others are decidedly generating extra layers, often even violating SRP by injecting DbContext into Aggregate Roots.

I'm terribly apologizing if I'm asking an opinion-based question, but...

When it comes to practice - Entity Framework is one of the most powerful and widely-used ORMs. You will not find a comprehensive course covering DDD with it, unfortunately.


Important aspects:

  • Entity Framework brings UoW & Repository (DbSet) out of the box

  • with EF your models have navigation properties

  • with EF all of the models are always available off DbContext (they are represented as a DbSet)

Pitfalls:

  • you cannot guarantee your child models are only affected via Aggregate Root - your models have navigation properties and it's possible to modify them and call dbContext.SaveChanges()

  • with DbContext you can access your every model, thus circumventing Aggregate Root

  • you can restrict access to the root object's children via ModelBuilder in OnModelCreating method by marking them as fields - I still don't believe it's the right way to go about DDD plus it's hard to evaluate what kind of adventures this may lead to in future (quite skeptical)

Conflicts:

  • without implementing another layer of repository which returns Aggregate we cannot even partly resolve the abovementioned pitfalls

  • by implementing an extra layer of repository we are ignoring the built-in features of EF (every DbSet is already a repo) and over-complicating the app


My conclusion:

Please pardon my ignorance, but based on the above info - it's either Entity Framework isn't adequate for Domain-Driven Design or the Domain-Driven Design is an imperfect and obsolete approach.

I suspect each of the approaches has its merits, but I'm completely lost now and don't have the slightest idea of how to reconcile EF with DDD.


If I'm wrong - could anyone at least detail a simple set of instructions (or even provide decent code examples) of how to go about DDD with EF, please?

  • I detailed steps here according to my understanding of how EF works. Still those steps don't handle a problem of accessing children by nav. properties or by DbSets off DbContext. – Alex Herman Jan 2 at 21:27
7

DDD and EF have little to nothing to do with each other.

DDD is a modeling concept. It means to think about the Domain, the Business Requirements, and model those. Especially in the context of object-orientation it means to create a design which mirrors business functions and capabilities.

EF is a persistence technology. It is mainly concerned with data and database records.

These two are sharply divorced. A DDD design may use EF in some form under the hood, but the two should not interact in any other way.

Some interpretations of Domain-Driven Design do actually advocate data-modeling, and I think this is what your question is about. In this interpretation "Entities" and "Value Objects" are essentially function-less data holders only, and the design concerns itself with what properties these hold and what relation they have between each other. In this context DDD vs. EF may come up.

This interpretation however is flawed, and I would strongly recommend ignoring it altogether.

In conclusion: DDD and EF are not mutually exclusive, they are actually irrelevant to each other, as long as you are doing proper object-modeling and not data-modeling. DDD objects should not in any shape or form be EF artifacts. DDD Entities should not be EF "entities" for example. Inside some business-relevant function, a DDD design might use EF with some related data-objects, but those should be always hidden under a business-relevant behavior-oriented interface.

  • 1
    EF just is just a time saver. Changes-tracking and persistence of aggregates is where EF already helps a lot. Unfortunately, currently there's no way to define the shape of aggregates at configuration level. – Pavel Voronin Feb 20 at 13:05
5

Treat EF for what it is i.e. data access library which is only slightly more strongly-typed than raw ADO.NET. I wouldn't recommend to model your domain using EF entity classes just like I wouldn't recommend to model domain using raw DataSet or DataTable.

I do understand that EF is being sold as a shortcut between database access and domain modeling however this approach is intrinsically flawed as it addresses two largely unrelated problems. There were other attempts in .NET to make a class perform some completely unrelated things (e.g. .NET Remoting) and they didn't end well.

Do the DDD using POCO classes and don't let database schema to drive your design. Keep EF inside repository/persistence layer and don't let the EF entities to leak outside.

4

Entity Framework brings UoW & Repository (DbSet) out of the box

No.

Entity Framework abstractions were built with ORM, not DDD, in mind. The DbSet abstraction in any version of Entity Framework is nowhere near the simplicity of a DDD Repository - not to mention DbContext which exposes a zillion things more than a UnitOfWork.

Here is a non-exhaustive list of elements in EF Core 2.1's abstract DbSet<TEntity> that we don't need in DDD:

  • Attach(TEntity) and all its siblings
  • Find(Object[])
  • Update(TEntity) and all its siblings
  • Implementing IQueryable

In addition to dragging along unneeded dependencies with them, these obscure the intent of a Repository which normally exposes very simple collection behavior. Plus the leaky abstractions are a constant temptation for developers to couple themselves way too much to EF and a threat to Separation of Concerns.

Bottom line: you must wrap these fatties into nice, streamlined concepts and guess what, that means introducing extra classes.

A relatively sound example of what you can do with EF and DDD (although some points of view expressed are debatable): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

others are decidedly generating extra layers, often even violating SRP by injecting DbContext into Aggregate Roots

I really don't see the connection between the two parts of this sentence. No matter the approach, there's a thing in DDD called Application Service and that's where you manipulate the Unit of Work/Repository (or DbContext). Not in Aggregate Roots.

While it could be a valid approach if it were an educated tradeoff, the recent anti-Repository, "Entity Framework minimalism" trend is delusional. It blames DDD patterns for the friction that happens with Entity Framework when it is really the EF creators that did nothing to make their framework compliant with best practices out of the box. All the while they are getting tightly coupled to that very framework with all the problems in terms of code safety and maintainability that can ensue.

2

Conflicts:

without implementing another layer of repository which returns Aggregate we cannot even >partly resolve the abovementioned pitfalls

by implementing an extra layer of repository we are ignoring the built-in features of EF (every DbSet is already a repo) and over-complicating the app

I have used an approach where every Aggregate gets its own DBContext, mapping just what is needed for the Aggregate. I think this has also been described by Julie Lerman.

This worked out very well, but might not suffice for more interesting models, where you don't want to link your concepts to your entities.

0

Just would like to share possible solution for consideration:

  1. avoid referencing EF project in Service Layer directly

  2. create an extra Repository Layer (uses EF project & returns Aggregate Root)

  3. reference the Repository Layer in Service Layer project

Architecture:

  • UI

  • Controller Layer

  • Service Layer

  • Repository Layer

  • Entity Framework

  • Core Project (contains EF models)


The pitfalls I see with this approach:

  • if a Repository returns Aggregate Root not as EF model tree (e.g. we return a mapped object) - we are losing EF's ability of tracking changes

  • if the Aggregate Root is a EF model - all of its navigation properties are still available, even though we can't deal with DbContext (we don't reference EF project in Service Layer)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.