0

Let's say we have a class Order (related to user) and it has property state. I want to prevent having more than one confirmed order in the same time so before I confirm any order I have to check if there is already some confirmed in it's time period.

I can make 2 approaches (I know of):

  1. OrderRepository has a function changeState which search for conflicting confirmed orders before changing it and allows it only when nothing is found - the problem here is repository knows about logic of changing state.

  2. OrderRespository is injected into Order and Order has function changeState which will use that repository to check for conflicts - here problem is the domain object know about persistence.

What is a right way to do?

hasumedic
  • 2,139
  • 12
  • 17
kuba
  • 3,670
  • 3
  • 31
  • 41
  • Possible duplicate of [Is it ok for entities to access repositories?](http://stackoverflow.com/questions/827670/is-it-ok-for-entities-to-access-repositories) – guillaume31 Sep 29 '16 at 07:58
  • Nope, been there and as I learned that 2nd approach is bad I still don't know how to handle it properly. – kuba Sep 29 '16 at 08:04
  • Then your Q title doesn't reflect what you're really looking for - you should change it. – guillaume31 Sep 29 '16 at 08:18

2 Answers2

2

Repositories are not in charge of domain invariants. Aggregates are. If no Aggregate has the needed info inside itself to check the invariant, try to question your aggregate design and maybe come up with a new one.

You can use a Domain Service, alternatively. As a weaker option, you could also degrade the domain invariant down to a simple use case precondition and have it checked by the Application Service/Command Handler. Note that the latter 2 options don't provide as strong a guarantee that domain entities will be in a consistent state at all times regarding that rule.

guillaume31
  • 13,738
  • 1
  • 32
  • 51
0

Another way to think about this would be from the point of view of a repository's responsibility. At the end of the day, a Repository is an abstraction to represent how to deal with a collection of objects, in your case, Orders.

Hence, it makes sense to keep rules around consistency and right state for the collection to be represented at the repository layer. Injecting repositories into entities is probably a code smell that something is not being modelled correctly. I'd go for your first version, but maybe you don't need to be specific about your state change, but simply embed those rules into the save() method. You can save the changes to an order iif there's no other confirmed at the same time.

hasumedic
  • 2,139
  • 12
  • 17
  • I don't really agree with this. Repository isn't a place where you would expect to find business rules. – guillaume31 Sep 29 '16 at 09:34
  • You're probably right from a purist point of view. But I've been into too many concurrency issues due to things like this (check andThen save) to keep being as purist. Unless the system is message driven, I'd be a bit more practical in this particular case. – hasumedic Sep 29 '16 at 09:47
  • I don't know. Even as a maintainer of the code, you wouldn't think of `OrderRepository` to be the place where conflicting orders rule is implemented. It goes against the principle of least surprise. This is very practical. – guillaume31 Sep 29 '16 at 09:53