Re: Re: When and where to raise AggregateRootAddedEvent
Wim van Gool <[email protected]>
| Newsgroups | gmane.comp.programming.domain-driven-design |
|---|---|
| Message-ID | <CAKqMafyWM62575S5NfMHGP=MhNqHodsSXD3FompGw=98kFnLcA@mail.gmail.com> |
@Dennis/Greg: I'll definitely consider refactoring my aggregates to use the more event-sourced/NCQRS-style of things. I can see the benefits it has over raising events on the spot. @Moran: There's always two things that I consider separate contexts: the transient context and the persistent one. If you have message-handlers that handle events transiently (to update read-models within the same transaction, for example), you've just made a conscience decision that you are handling events that have not been stored/committed yet, so those handlers should take this into account. As such, I don't see any *real* problem with raising events inside an aggregate that has just changed state. However, even in the transient context, I expect aggregates to be accessible through my repository when an event is raised that it's been created/added (you just pick it out of memory then), but this only works if you always raise this event after the _repo.Add(newAggregate)-call. This is why I feel this is a special case. On Mon, Jun 24, 2013 at 9:35 PM, Moran Lefler <[email protected]> wrote: > ** > > > The point that you are raising bugs me as well. > I see it as a more general concern, since the same question can be asked > about any change of state within the domain model - Do we raise the domain > event as soon as the model changes, or only when the change is actually > committed to the store? As you mention, triggering the event from the > domain model may cause other handlers to act upon that knowledge, querying > stale data from the db, and even may in turn trigger other events and so on > - think of all the compensation logic that have to rollback all of that > action, in case of a e.g. a transaction failure. > > I would very much like to hear the group's opinion on that matter. > > Cheers, > Moran > > > --- In [email protected], Wim van Gool <vangool.w@...> > wrote: > > > > While implementing my example DDD-project, there's one thing that's still > > not very clear to me at this point, mainly because I see so many samples > > and advise that contradict each other or sometimes raise more questions > > than they answer. Yet, ironically, it's actually core to implementing a > > DDD-application, IMHO. > > > > Suppose I must add/create a new aggregate, what thing is responsible for > > raising the *NewAggregateAddedEvent*, and when to raise it? Note that I'm > > > not applying event-sourcing; I just use plain state-based aggregates and > > repositories. > > > > *Option 1: Let your ApplicationService/MessageHandler take care of it* > > > One way of doing this is the most simple thing, something like this: > > > > public sealed class AddNewCarHandler : IMessageHandler<AddNewCarCommand> > > { > > private readonly ICarRepository _repository; > > > > .... > > > > public void Handle(AddNewCarCommand command) > > { > > // Create the new Car somehow > > Car newCar = _carFactory.AssembleNewCar(...); > > > > _repository.Add(newCar); > > > > DomainEventBus.Publish(new ...()); > > } > > } > > > > This is the way I have been doing it so far. The advantage of doing it > this > > way is that it's pretty straightforward and simple. The downside is that > I > > now my application-layer is raising domain events, which is not something > > that it's 'supposed to do' I guess. That's why I'm questioning this > > approach. > > > > *Option 2: Let your factory-method publish the event* > > > This is the way Vaughn Vernon explains it is his book (paragraph on > > creating Discussion instances), which basically means that, in my own > > example, method AssembleNewCar() would call DomainEventBus.Publish(..) > > inside before returning. > > > > The advantage of doing it this way is that domain events are only raised > > inside the domain, but there's a caveat that I see here: the domain event > > is now raised *before* the aggregate (Car in this case) is actually added > > > to the repository. If you have hooked up any handlers that get invoked > > within the same transaction, they might expect the new aggregate to be > > present in the repository and attempt to retrieve it. If having such > > handlers in the first place is a smell in itself I'd like to here this > > though... Moreover, this problem could be tackled by attaching the newly > > created aggregate to the created event, but I'd like to avoid this if > > possible and only communicate using id's where I can. > > > > *Option 3: Create a domain-service.* > > > Another option that tackles both 'problems' of the two above is to > create a > > separate domain service like AddNewCarService to your domain and let the > > application-service basically delegate it's work to this service - with > the > > exception of translating the command to appropriate domain-values/objects > > of course. Needless to say, this does require extra domain services to be > > created for the sole purpose of adding new aggregates, which I haven't > seen > > much in code samples and so makes me think this is not a typical > > (desirable?) way of doing things. > > > > So, how are you guys doing this? > > > > >