0

I have an Aggregate Root (AR1) that references another Aggregate Root (AR2) by Identity. i.e. as discussed here http://www.informit.com/articles/article.aspx?p=2020371&seqNum=4

Now in one of my methods in AR1 I need to access the full object of AR2 to perform a check. I have created a domain service called AR2DomainService and that is now being injected into the method of AR1. For example:

public class AR1 
{
     public Guid AR2Id; 

     public void DoSomething(IAR2DomainService, aR2DomainService)
     {
        AR2 ar2 = ar2DomainService.GetById(Ar2Id);

        if(ar2.status != Status.OK)
            //throw exception

        //do some processing. 

     }

     public bool DomSomething2(IAR2DomainService, ar2DomainService)
     {
          return ar2DomainService.DoSomething(Ar2Id); 
     }


}

Is this code ok?

Cool Breeze
  • 1,289
  • 11
  • 34
  • keep in mind I am never really modifying AR2... I am only ever reading properties. – Cool Breeze Nov 21 '14 at 13:43
  • 4
    What will happen if ar2 state gets modified at the same time this code runs? You might end up with an invalid state. Also, domain services aren't meant to rehydrate aggregates, repositories are. Other than this, there might be nothing wrong in injecting a domain service in an AR method, but always try to pass the most explicit dependency. E.g. passing ar2 rather than a service to retrieve ar2. – plalx Nov 21 '14 at 21:49
  • Can you describe the business scenario using real domain semantics like "transfer an amount of money from a source to a beneficiary account". Otherwise we wont able to help you in the right direction. – Sebastian Oliveri Nov 24 '14 at 02:39
  • It's related to this post here: http://stackoverflow.com/questions/27039878/concerned-about-the-size-of-my-aggregate-root?noredirect=1#comment42694814_27039878 – Cool Breeze Nov 24 '14 at 03:28

1 Answers1

3

As plalx points out, Domain Services aren't here to retrieve aggregates. What I would do is coordinate everything from the Application Service/Command Handler. It reads the associated Aggregate Root ID from AR1, and retrieves it through a Repository. Then it can extract relevant information from AR2 and pass it as a parameter to AR1's method. Note that the smaller this parameter, the better. Ideally you wouldn't pass AR2 entirely but only a Value Object containing the minimum information needed (you don't want to be tempted to update AR2 as part of a transaction in AR1).

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • I was only ever using AR2 to perform a check not to actually update it. Whether you inject a domain service or inject the actual value from the application service. isn't it subject to the same issue i.e. concurrency? – Cool Breeze Nov 24 '14 at 23:54
  • Sure. I was only addressing the dependency side of your question. The concurrency problem might be a non-problem if it's acceptable for `AR1` to reason about `AR2` data dating back a few milliseconds, which is hard to tell without knowing your real domain. If it's not acceptable, you should either review your aggregate design, introduce eventual consistency tactics, or have the applicative transaction span the 2 aggregates (not recommended in an "Aggregate as transactional boundary" approach). – guillaume31 Nov 25 '14 at 13:24
  • In my particular scenario concurrency is not a problem so I guess I will just inject AR2 into the method of AR1 and perform the check. – Cool Breeze Nov 26 '14 at 01:29