DataAccess Layer coupling with Domain Layer

by jan   Last Updated October 10, 2019 10:05 AM

We have an issue with how the implementation of the Data Access layer (EF6 Includes more specifically), influences the behavior of our Domain layer.

A theoretical example to illustrate:

Application in 3 layers, DDD:

  • Domain layer: simplistic domain model

    • An Order has Orderlines
    • An Order has a public property "CanBeExtended". Business logic is
      "when there are less than 10 Orderlines, an order can be extended"
    • Note: This implementation is unit testable, no dependencies
  • Data Access layer: this layer contains the OrderRepository, which uses EF6 to retrieve an Order object from the database.

    • GetOrderById is the only relevant method for this example
    • References the Domain layer.
  • Service layer: contains "Controllers" in MVC-speak, is accessed via the API

    • References both Data Access and Domain layer
    • Exposes a method "CanOrderBeExtended": input is the id of the order, returns a bool whether the order can be extended

Implementation of this Service layer: Retrieve the Order object from the repository using GetOrderById, then call its property CanBeExtended, and return that value.

Problem: Depending on the implementation of the Data Access layer, the Domain layer behaves wrong: depending on whether you Include the Orderlines of the Order in GetOrderById, the CanBeExtended behaves differently.

The Bug: When you forget the Include, all Orders are extendable.

Possible solutions:

  1. Lazy loading is considered, but it's not our favorite. It's a technical detail of EF6, and it might turn out to be problematic in a late stage, and highly dependent on the actual setup: db server access speed,...

We're looking for a more fundamental solution:
How can we mitigate this dependency between the Domain and the Data Access layer?
How can we make sure we don't forget Includes?

  1. Making multiple and specific methods on the repository is considered as well, but it doesn't appear to scale well:

This example might then use something like "GetOrderWithOrderLinesById" which contains the Include(o => o.OrderLines).
But to decide which method is needed, we'd have to review the implementation of CanBeExtended in the Domain layer.
Additionally, when that implementation changes, the repository method needs to change as well (e.g. to add extra Include statements), or another, new method would turn out to be needed, thus highly coupling the Repository (in the Data Access layer) with the Domain layer.

Fowler nor Evans seem to touch this specific topic AFAIK.

Any and all thoughts welcome!

Related Questions

Updated January 26, 2019 11:05 AM

Updated October 16, 2017 20:05 PM

Updated October 17, 2017 19:05 PM

Updated September 11, 2016 09:02 AM

Updated September 25, 2018 07:05 AM