Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
175 views
in Technique[技术] by (71.8m points)

Should operations on aggregate root that cause changes in child entities raise the child domain events?

Let's say that we have an Entity (the Root) with a property identifier, and another Entity (a child / local entity to Root) with a property name, with the rule that the Child's name must start with the Root identifier. There is a changeIdentifier operation and a renameChild operation, and the Child::name property must always be consistent with the Root identifier.

The renameChild operation, after checking the validity of the new name, raises a ChildRenamed domain event, containing the Root and the Child identities and the new name value.

The chengeIdentifier operation changes the Root's identifier and raises a RootIdentifierChanged event, then goes on and changes all the Child's names. What should happen now? Should ChildRenamed events be raised or not? And are importantly, why? What is the rationale behind one choice or the other? I guess the answer also depends on the event being raised from the Root or the Child.

class Root extends AggregateRoot {
  private GUID _identity
  private name _identifier
  private Collection<Child> _children

  function changeIdentifier(newIdentifier: string): void {
    oldIdentifier = _identifier
    _identifier = newIdentifier

    addDomainEvent(new RootIdentifierChanged(_identity, _identifier))

    // this...
    // raises `ChildRenamed` events
    for (child in _children) {
      newName = child.name().replace(oldIdentifier, _identifier, STR_START)
      renameChild(child.identity(), newName)
    }

    // ... or this
    // no `ChildRenamed` events raised
    for (child in _children) {
      newName = child.name().replace(oldIdentifier, _identifier, STR_START)
      child.rename(newName)
    }

    // ... or event this?
    // `ChildRenamed` events raised or not depending on
    // `renameAfterRootIdentifierChange` implementation
    for (child in _children) {
      child.renameAfterRootIdentifierChange(_identifier)
    }
  }

  function renameChild(childIdentity: GUID, newName: string): void {
    checkRule(new ChildNameIsConsistent(_identifier, newName))

    child = _children.find(fn(child) => child.identity().is(childIdentity))
    child.rename(newName) // the event is not raised here, in the child...

   // ... but here, in the root
    addDomainEvent(new ChildRenamed(_identity, child.identity(), newName))
  }
}
question from:https://stackoverflow.com/questions/65887683/should-operations-on-aggregate-root-that-cause-changes-in-child-entities-raise-t

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

From my experience the best way is to collect all events from all child entities in the aggregate root and make this list of raised events available from the aggregate.

With that the raising/creation of the events and the actual dispatching of the events to the subscribing components can be separated.

This allows to not dispatch any events if something along the business transaction goes wrong on the way.

I also often use a similar approach for collecting errors raised by child entities as outlined in this answer: https://stackoverflow.com/a/60863098/7730554

Update in order to take the comment into account:

I prefer using a base domain entity class which provides the functionality to add, merge and query the events which is used by both aggregates and entities to avoid code duplication.

From my point-of-view, an aggregate has to know about it's children anyway. If, in some situations the child entity has a child entity by itself (which I try to avoid if possible to avoid deep trees of children and making aggregates too big and complex) it can use the same functionality to query it's child events again.

With this approach no entity - be it the aggregate root or any child entity - needs to know where to push events to and does not have to care about who and when will query the list of events.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...