Getting all aggregate root entities child entities?
Asked Answered
H

2

5

I am attempting to refactor my application from a repository per entity to a repository per aggregate root.

A basic example would be I have an entity root of Cars. Cars have hire contracts. As far as I can see contracts don't exist without cars hence cars is the aggregate root.

I am trying to implement a user view which will shows every contract in the system(all the child entities of the root entities). Before refactoring I could just go to my contracts repository and get All. As contracts repository has been removed (as its not a root) I now need to get all cars out of my repository and then get all their contracts.

My repository has the interface

public interface ICarRepository
{
    IQueryable<Car> All { get; }
    IQueryable<Car> AllIncluding(params Expression<Func<Car, object>>[] includeProperties);
    Car Find(long id);
    void InsertOrUpdate(Car car);
    void Delete(long id);
    void Save();
}

I thought of creating an ICarManagementService and having it have a GetAllContracts method (perhaps with filter parameters). Would that mean to get all contracts I need to pull all car entities out with their contracts and then retrieve each entities associated hire contracts and filter them?

I can then pass these to the controller and AutoMap the contracts as before.

Is this best practice?

Thanks

Graeme

Hausner answered 18/9, 2011 at 10:42 Comment(0)
D
5

As far as I can see contracts don't exist without cars hence cars is the aggregate root.

This is not necessarily true. 'Don't exist without' is not enough for an entity to become a part of an Aggregate Root. Consider classic order processing domain. You have an Order that is an Aggregate Root. You also have a Customer that is an Aggregate Root. Order can not exist without a Customer but it does not mean that Orders are part of the Customer Aggregate. In DDD entities inside one Aggregate can have references to other Aggregate Roots. From DDD book:

Objects within the AGGREGATE can hold references to other AGGREGATE roots.

Aggregate is a life cycle and data exchange unit. It is essentially a cluster of objects that enforces invariants. This is something you want to be locked if you have multiple users changing domain at the same time.

Back to your question, my understanding is that the domain is something like rent / lease a car / truck / limo / bulldozer. I think that HireContract may not be a part of Car aggregate because they may have different lifecycles and HireContract just makes sense on its own, without a Car. It seem to be more of a Order-Product relationship that is also a classic example of two different Aggregates referencing each other. This theory is also confirmed by the fact that business needs to see "All Contracts". They probably don't think of Car containing all Contracts. If this is true than you need to keep your ContractsRepository.

On an unrelated note, you might be interested in reading this answer about repository interface design.

Doorn answered 18/9, 2011 at 12:38 Comment(3)
I did think I wanted people to be able to lock "Cars" for editing. I can see hire contracts as an aggregate. I need to prevent people being able to add overlapping hire periods. Can I still enforce that if hires is an aggregate.Hausner
Hard to answer this question without having a good understanding of your domain. But I can give you a hint. There is a method mentioned by Udi Dahan and/or Greg Young that you should try to imagine how would this functionality be implemented in 'paper-based' business, without computers. This may lead into more asynchronous approach (allowing hiring period overlaps temporarily like Amazon allows two customers to order the book even if only 1 is left in stock, and then notifies you by email). A lot can be achieved if you remove "everything should be 100% consistent all the time" restriction.Doorn
Will possibly post a more detailed question later. My copy of the blue book should arrive this week so hopefully I will get a better grip on good DDD practice. Thanks for the help.Hausner
M
4

Separate the concept of read/query from the write/command, as guided by CQRS it is preferable to design the application by separating read model which consists of read only queries and the write model on the other hand which consists of commands to execute certain logic on the domain model.

thus querying all aggregate roots or creating custom queries to join sets of data is not a good candidate of domain repository, instead put these queries into read repository (or better named Finders).

if you find yourself wanting to query a collection of objects in order to execute some domain logic then it is an indicator that you have to abstract this collection and put it into an aggregate root to encapsulate them and make the business operation or method act on them.

check out (http://moh-abed.com/2011/09/13/pure-old-ddd-with-a-twist-from-cqrs/) and (http://simon-says-architecture.com/2011/08/23/repository)

Millenarianism answered 18/9, 2011 at 11:48 Comment(2)
These links are dead, it's good to quote the essential parts in the answer. Luckily, old snapshots are present in web.archive.org/web/20150531070309/http://moh-abed.com/2011/09/… and web.archive.org/web/20160403195814/http://…Paronymous
However, this is a good answer. DDD's aggregate roots are actually only about command's execution/change scope,.. But, there are different read-only view concerns, where it does not make sense to think in aggregate roots, e.g. aggregate queries for statistics, reports, dashboard elements...Paronymous

© 2022 - 2024 — McMap. All rights reserved.