C# – Should a Rich Domain Model have repositories injected in some situations

cdesign-patternsdomain-driven-design

Please see the code below, which I took from Jimmy Bogards wicked domain models:

public Offer AssignOffer(OfferType offerType, IOfferValueCalculator valueCalculator)
        {
            DateTime dateExpiring = offerType.CalculateExpirationDate();
            int value = valueCalculator.CalculateValue(this, offerType);

            var offer = new Offer(this, offerType, dateExpiring, value);

            _assignedOffers.Add(offer);

            NumberOfActiveOffers++;

            return offer;
        }

Unfortunately he has not posted the code contained in the implementation of: IOfferValueCalculator. I have a feeling that the class will contain logic that determines what offers a member is entitled to. However, surely the domain object has to go to the database (via the repository) to get details of the offers e.g. date expiring etc. However, I understand that the domain layer in a rich domain model should not go to the database. Therefore how does the domain layer get the offers? Are all the offers injected into the domain layer by the application layer?

I believe there is a pattern here that I am missing? I already know of Command Responsibility Segregation. However, I believe in my case that the command object needs to access the database.

Best Answer

If you need to access a database to solve your particular problem, then... Well, you need to access a database. Doesn't matter what Jimmy Bogards, Eric Evans or anyone else says. If their rules don't allow you to do that, then break their rules, follow someone else's rules, or make up your own.

When you read some rule on the internet that someone has devised, try to understand the motivations behind it first, before you apply it. That way, you have a reasonable assurance that the application of said rule aligns with your own needs and expectations.

Rules like the one you cited from Eric Evans generally have one of two motivations:

  1. Separation of Concerns, and
  2. Decoupling.

Separation of Concerns mostly means "write each class or method so that it has one area of expertise and does that well." Often, that means writing some module that specializes in database access only, allowing other modules/classes to focus on their own specific concerns without being concerned with the details of data retrieval. It also means that your classes can be "persistent-ignorant," meaning they don't have to know how to save or retrieve themselves from a database, especially some specific database technology.

Decoupling, within the context of database access, generally means one of two things:

  1. You want to isolate data retrieval from the rest of the system, just in case you might someday change out the database implementation for something else, or
  2. You want to mock the data retrieval mechanism for unit testing purposes.

There are two commonly-accepted ways to access data from a database. The first way is to use CRUD operations (create, read, update, delete). The second is to provide a Business Logic Layer. A business logic layer has methods on it like GetOffers() which provides more intelligent (and optimized) retrieval of data than create, read, update and delete.

Now then. Jimmy Bogard's Wicked Domain Models:

What is a domain model?

An object model of the domain that incorporates both behavior and data.

Why should I care?

A lot of times – you shouldn’t.

When you should – complex domain, or a long-lived project where behavior gets added piece by piece.

So even Jimmy Bogard says "use it only if you need it."

Many software developers today suffer from "Pattern-Matching disease." They think everything in software development is a pattern, and that writing a program is an exercise in stitching patterns together. Unfortunately, that's not quite the way it works, nor is slavishly following somebody's ideas about "best practices" without understanding why.