The repository pattern suggest that you can only pull aggregate roots. But how would you retrieve a single child using only it's uniqiue identity(Child.ID) if you do not know it's parent(root)?
class Parent
{
public int ID { get; set; }
IEnumerable<Child> Children { get; private set; }
}
class Child
{
public int ID { get; private set; }
public virtual Parent Parent { get; private set; } // Navigational model
}
My application is stateless (web), for simplicity, the request only contains the ID of the child.
I am thinking three approaches:
- Call all the parents then ask them politely who owns this child.
- Have a special routine in the ParentRepository called get GetChildByID, which kinda fails the repository's abstraction.
- Modify the request to include the parent, but seems unnecessary since you already have a unique identity.
It seems likely that you're actually looking at a different bounded context here. You mentioned in your question that "repository ... can only pull aggregate roots."; this is correct. Another answer also mentions that if you need to query a child object, the child object may also be an aggregate root. This may also be correct within a different bounded context. It's quite possible for an entity to be an aggregate root in one context, and a value entity in another.
Take for example the domain of Users
and the mobile/tablet Apps
they have installed on their devices. In the context of the user, we might want the users basic properties such as name, age etc, and we might also want a list of apps the user has installed on their device. In this context User
is the aggregate root and App
is a value object.
bounded context UserApps
{
aggregate root User
{
Id : Guid
Name : string
Age : int
InstalledApps : App list
}
value object App
{
Id : Guid
Name : string
Publisher : string
Category : enum
}
}
In another context we may take an App
centric view of the world and decide that App
is the aggregate root. Say for example we wanted to report which users have installed a given app.
bounded context AppUsers
{
aggregate root App
{
Id : Guid
Name : string
InstalledBy : User list
}
value object User
{
Id : Guid
Name : string
InstalledOn : Date
}
}
Both of these bounded contexts would have their own repository which returns the respective aggregate root. There's a subtle but crucial difference in your perspective of the data.
I think if you take a step back and think about why you want to query for a child object, you might find that you're actually in an entirely separate bounded context.
If you require the child for display/reporting/viewing/reporting then a simple query layer will do.
If you are manipulating the child in any way then it has a consistency boundary and it sounds an awful lot like an aggregate.
Try not to query your domain objects. Another simple rule of thumb is not not include an aggregate reference in another aggregate but to rather use just the referenced aggregate's Id or even a value object representing the relationship.
Entity navigation is not a purpose of a domain model.
An Aggregate Root is a composition of Entities and Values that expose business operations.
As a side effect, you can still perform some simple query or navigation through your AR, but, for complex querying, creating and using a Query Model is more efficient.
I'm talking about CQRS.
Hope this can help you.
来源:https://stackoverflow.com/questions/20189421/searching-for-a-child-across-aggregate-roots