Child Entities in CQRS

939 views
Skip to first unread message

Kyle Bradley

unread,
Jul 21, 2015, 4:33:01 AM7/21/15
to ddd...@googlegroups.com
Hi

I'm implementing my first project using DDD/CQRS with the NEventStore package. One technicality that I'm struggling to find resources on is the way one should handle non-aggregate root events. 

I stumbled across this example in my research, but I don't necessarily agree with it. https://github.com/pjvds/Scrumr/blob/master/src/Scrumr.Domain/Project.cs (line 81: AddSprint)

My issue with this approach is that the "new Sprint ()" should have validation within the constructor preventing invalid parameters. This breaks one of Greg Young's rules, which is that the apply methods purely set and aren't able to fail on exception. 

General questions:
  • How should the creation of the child entity be handled?
  • Commands are obviously handled by the AR, but what about child entity specific events? Should the AR handle this then call a method on the child or can the child handle this.
  • (Unrelated) Events are immutable and unchanging once published, whereas value objects can be changed. When needing to include a VO within an event should you duplicate the needed data in the event, create an event specific value object model or can you reference the value object? E.g. I have a "Location" class that stores a latitude and longitude. Can I store that VO directly in an event? What happens if I add another property to it?
Regards
Kyle

Freek Paans

unread,
Jul 21, 2015, 5:39:00 AM7/21/15
to ddd...@googlegroups.com
Inline

I stumbled across this example in my research, but I don't necessarily agree with it. https://github.com/pjvds/Scrumr/blob/master/src/Scrumr.Domain/Project.cs (line 81: AddSprint)

My issue with this approach is that the "new Sprint ()" should have validation within the constructor preventing invalid parameters. This breaks one of Greg Young's rules, which is that the apply methods purely set and aren't able to fail on exception. 

In the end it's the responsibility of the AR to enforce the invariants. In this case it accepts all values for the sprint. If there were any rules, they would be enforced before ApplyEvent(new SprintAddedToProject(sprintId, name, from, to)); though not necessarily in the Sprint ctor (that's just implementation).
 

General questions:
  • How should the creation of the child entity be handled?
Think the above solution is fine. 
  • Commands are obviously handled by the AR, but what about child entity specific events? Should the AR handle this then call a method on the child or can the child handle this.
I always let the AR handle it, then forward it to the child entity. The reason being it usually doesn't make sense to instantiate the child without its AR.
 
  • (Unrelated) Events are immutable and unchanging once published, whereas value objects can be changed. When needing to include a VO within an event should you duplicate the needed data in the event, create an event specific value object model or can you reference the value object? E.g. I have a "Location" class that stores a latitude and longitude. Can I store that VO directly in an event? What happens if I add another property to it?
What you need here is a DTO, not a value object. VO's are not generally used to store data (and they usually are immutable)

Cheers,

-Freek

Kyle Bradley

unread,
Jul 21, 2015, 6:46:20 AM7/21/15
to ddd...@googlegroups.com
Thanks for the prompt response.

The way I saw it, which must be incorrect, was that the AR handled the cross child-entity invariants and the child handled its own. Can see the advantages of having the AR handle all invariants, but I'm concerned that it will bloat the AR up. Instead some of that logic could be encapsulated within the child entity. 

For example, say the sprint had a start and end date. As a result, a rule would be that the start date must be before the end date, but following this, that logic would be in the AR. Would be nice to have the entity describe itself, rather than the AR describe it.  

Freek Paans

unread,
Jul 21, 2015, 6:57:30 AM7/21/15
to ddd...@googlegroups.com
Yes, it can delegate those responsibilities to child classes, but from an outside-of-the-aggregate point of view it's a responsibility of the aggregate as a whole. How that's implemented is a different matter though, and indeed that logic would usually be implemented in classes representing the child entities.
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kyle Bradley

unread,
Jul 21, 2015, 7:16:44 AM7/21/15
to ddd...@googlegroups.com
I agree with you, but it's the implementation that is my concern though. 

Having the invariant logic being in the child entity creates a problem. The AR's properties should only be modified through events, but events shouldn't be able to fail (which could happen if logic is within the ctor). You almost want a child entity validator, which is used in the command method so, when you call the childEntityAdded event, it won't throw an exception.

I could be making this more complicated than it should be.

Freek Paans

unread,
Jul 21, 2015, 7:28:13 AM7/21/15
to ddd...@googlegroups.com
If the ctor fails while handling the command, the event won't make it into the aggregate's events. So the only problem occurs when you change the implementation of the Sprint constructor, but this problem is not specific to ctors or child classes. For example, if _sprints isn't initialized (is null), the application of the event will also fail.

Kyle Bradley

unread,
Jul 21, 2015, 7:41:52 AM7/21/15
to ddd...@googlegroups.com
Thanks, that actually makes sense. Forgot that if the apply event fails on the initial apply that it would propagate to the command and not commit the event.

Appreciate it!

Kijana Woodard

unread,
Jul 21, 2015, 11:42:05 AM7/21/15
to ddd...@googlegroups.com
- A command can define for itself what it means to be valid [e.g. start date before end date]. You could do that check in  the ctor or in a factory method. That means that downstream handlers, including the aggregate and entity are assured of a base level of correctness.

- The aggregate can determine correctness for the command in the context of the current aggregate state [e.g. you can't have a start date earlier than another sprint or something].

- From the point of view the rest of the universe outside the aggregate, there is only the aggregate. The fact that there are entities and that the aggregate may or may not delegate some invariant checking to those entities is immaterial to the rest of the system. As Freek said, it's the aggregate's responsibility to safeguard the invariants. If "it chooses" to delegate that responsibility, so be it. No one can say that's right or wrong. It's an implementation detail. The only "wrong" is that the invariants aren't protected.

- To supplement the part about events, let's say there's a situation where the business rules change such that some existing events could no longer be created. For those existing events, this is a non-issue.  They are immutable. They don't change. They don't disappear. 

mynkow

unread,
Jul 28, 2015, 6:41:30 PM7/28/15
to DDD/CQRS, kbrad...@gmail.com
I will share how we do this in our projects.

First you start with entities. You define invariants, events, logic etc. Usually the application service (command handler) is responsible for the creation of these entities (one level up). At some point you may find invariants between these entities and you define an aggregate with an entity which will acts as an aggregate root. You still have the entities handling their own invariants however there is no way the application service to create the entities which are now hidden behind the aggregate root. We make our aggregate roots responsible for creating the entities (one level up) and the validation for this task is done in the aggregate root. If we need to expose an entity function outside of the aggregate we just wrap the function in the aggregate root but let the entity to handle its own invariants.

I think that it is really bad idea to have the aggregate root responsible for the entities invariants. This breaks most of the stuff described in the blue book.

Note to all: Guys, make a difference between an aggregate and an aggregate root. There is a huge misunderstanding in your replies when you call aggregate root => aggregate. And what is AR? Aggregate or AggregateRoot? Please try to be more precise. 10x

@yreynhout

unread,
Jul 29, 2015, 6:41:54 AM7/29/15
to DDD/CQRS, kbrad...@gmail.com, myn...@gmail.com
To add to this, when using eventsourcing in something like C#, I usually have the aggregate root handle events for "other" entities within the aggregate and route it to the proper "other" entity. Put another way, the aggregate root acts as a factory, router, and destroyer of "other" entities within the boundary of the aggregate (for entities other than the root itself). All events still go thru the root, but optionally the entity can handle the event itself as well (if the root tells it to). As an aside, I can see a similarity with actors spawning, routing messages to, and destroying other actors.

There is a flavor of all this by which you expose an entity (using a getter, a collection, or a "find" like method) on the aggregate root and allow the caller to invoke a method on said entity. If the entity knows its root (direct reference or observer style or via collection), it can still ask/tell the root to enforce overarching invariants, without the caller even being aware that is going on (nor should it). This technique has limited uses, but it keeps the aggregate root's api surface smaller (it's a trade-off in the end).

Kyle Bradley

unread,
Jul 30, 2015, 4:45:31 AM7/30/15
to DDD/CQRS, myn...@gmail.com, yves.r...@gmail.com
I appreciate the comments. I understand the theory and goals behind the aggregate roots and their children but the issue lies with the implementation of it.

I'm trying to find the best way to implement this that adheres to the principles of CQRS. @yreynhout, found myself programming it in the way you mentioned above but to me it still has one shortfall which I will try explain below. I'm interested if there is a code example of either approach, or any Aggregate Root/Child relationship.

Have an aggregate root of "Routes" with a child entity of tripDefinitions. 







I expose a method that adds to this child entity on the AR. 

























Here is the event handler







In the constructor I have the child entity's in-variance checks:













This approach will have to suffice, but to me it breaks one of the rules of CQRS. Event apply methods should only set properties without ever throwing an exception. The reason is cause the child entity is created in the event, so it can throw an exception.

João Bragança

unread,
Jul 30, 2015, 5:31:31 AM7/30/15
to ddd...@googlegroups.com
You can avoid that with this pattern:

//your aggregate
public void DoSomething(DateTime startDate, DateTime endDate)
{
    ApplyChange(TripDefinition.For(startDate, endDate));
}

void Apply(SomethingHappened e)
{
    var tripDefinition = new TripDefinition(this.ApplyChange);
    tripDefinition.ApplyChange(e);
    tripDefinitions.Add(tripDefinition);
}
void Apply(SomethingElseHappened e)
{
    tripDefinitions[e.Id].ApplyChange(e);
}

public class TripDefinition
{
    public static SomethingHappened For(DateTime startDate, DateTime endDate)
    {
        if (endDate < startDate) 
        {
            throw new InvalidOperationException();
        }

        return new SomethingHappened{...};
    }
    public TripDefinition(Action<Event> apply)
    {
        _apply = apply;
    }

    public void SomeOtherBehavior()
    {
         _apply(new SomethingElseHappened(...));
    }

    public void ApplyChange(Event e)
    {
        // reflection magic thing
    }

    void Apply(SomethingHappened e)
    {
        _startDate = e.StartDate;
        _endDate = e.EndDate;
    }
    void Apply(SomethingElseHappened e)
    {
        _someOtherState = e.SomeOtherState;
    }
}

It's a bit weird that an event is returned from a static method on your entity but eh, it works. That being said, I would use a value object containing startDate / endDate to do that validation.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

@yreynhout

unread,
Jul 30, 2015, 8:50:59 AM7/30/15
to DDD/CQRS, joao...@braganca.name
What he said. The point is, don't put validation logic in the constructor used for rehydration. You don't do it for the root, so neither should you for the entity.
Other than that, try a dedicated collection for TripDefinitions. That'll dry up some of the Linq verbosity.

Greg Young

unread,
Jul 30, 2015, 8:54:00 AM7/30/15
to ddd...@googlegroups.com, João Bragança
This also brings back the same question with an ORM should you validate your state on hydration? There are pros and cons to it.
Studying for the Turing test

Kyle Bradley

unread,
Jul 31, 2015, 10:16:29 AM7/31/15
to DDD/CQRS, joao...@braganca.name, gregor...@gmail.com
This pattern is exactly what I am looking for. Removes the checks from the hydration method, which is what I wanted to accomplish. Thanks!
Reply all
Reply to author
Forward
0 new messages