tlt
tlt

Reputation: 15221

Dependent entities within same aggregate

Situation:

We have a classic Order with OrderLines. Each OrderLine has reference to the ProductId.

Each Product has its RelatedProduct. For example, product

class Product {
   string Id;
   string Name;
   string RelatedProductId;
   decimal RelatedProductQuantity;
   .
   .
   .
}

There is a business rule that whenever Product is added to Order with new OrderLine then Product with id=RelatedProductId should also be added in a quantity=RelatedProductQuantity.

Questions:

  1. How to keep this rule within the domain so it doesn't spill over to application service but at the same time keep Order aggregate clean in a sense not to poison it by injecting repository or any data-fetching thing?

  2. Should we use domain service? And if so, can domain service have repository injected, prepare all the data, create OrderLine (for both, base and related products), fill in the aggregate and save it to repository?

  3. If none of the above, what's the best way to model it?

Upvotes: 1

Views: 490

Answers (1)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57249

There are two common patterns that you will see here:

  • Fetch a copy of the information in your application code, then pass that information to the domain model as an argument
  • Pass the capability to fetch the information as an argument to the domain model

The second option is your classic "domain service" approach, where you use a "stateless" instance to fetch a copy of "global" state.

But, with the right perspective you might recognize that the first approach is the same mechanism - only it's the application code, rather than the domain code, that fetches the copy of the information.

In both cases, it's still the domain model deciding what to do with the copy of the information, so that's all right.


Possible tie breakers:

If the information you need to copy isn't local (ie: you are dealing with a distributed system, and the information isn't available in a local cache), then fetching that information will have failure modes, and you probably don't want to pollute the domain model with a bunch of code to handle that (in much the same way that you don't pollute your domain code with a bunch of database related concerns).

When it's hard to guess in advance which arguments are going to be passed to fetch the data, then it may make sense to let the domain code invoke that function directly. Otherwise, you end up with the application code asking the domain model for the arguments, and the passing the information back into the model, and this could even ping pong back and forth several times.

(Not that it can't be done: you can make it work - what's less clear is how happy you are going to be maintaining the code).

If you aren't sure... use the approach that feels more familiar.

Upvotes: 1

Related Questions