Re: Re: When and where to raise AggregateRootAddedEvent
Wim van Gool <[email protected]>
| Newsgroups | gmane.comp.programming.domain-driven-design |
|---|---|
| Message-ID | <CAKqMafyrgY2L=D2q_3tzcees0zHnKu8NPr_afWerf8_wTS5p+w@mail.gmail.com> |
@Johan: certainly an interesting approach, but what about methods that may or may not change state, of change state differently depending on current state (typical case, naturally). I think you'll have to return IEnumerable<IDomainEvent> from virtually every method call then, wouldn't you? And what if certain methods actually require a(nother) return value for itself? I mean, it's an interesting concept, and there's certainly ways to make it work, but it needs a bit of more investigation I guess. @Mauro: that is - I think - how Greg meant it as well. I take it that your aggregates keep a record of domain events until the repository commits and publishes them, much like event sourced aggregates? On Tue, Jun 25, 2013 at 8:14 PM, Mauro Servienti <[email protected]> wrote: > ** > > > We use the following approach and we are quite happy, no issues at all.** > ** > > C# code**** > > ** ** > > using( var repository = repositoryFactory.OpenSession() )**** > > {**** > > var aggregate = repository.Get<MyAggregate>( *aggregate-id* );**** > > aggregate.DoSomethingInteresting();**** > > ** ** > > repository.CommitChanges();**** > > }**** > > ** ** > > At “CommitChanges” stuff is saved to the storage and events raised by the > aggregate are propagated to the infrastructure by the repository, within a > transaction boundary.**** > > ** ** > > .m**** > > ** ** > > *From:* [email protected] [mailto: > [email protected]] *On Behalf Of *Johan Haleby > *Sent:* martedì 25 giugno 2013 07.52 > *To:* [email protected] > *Subject:* Re: [domaindrivendesign] Re: When and where to raise > AggregateRootAddedEvent**** > > ** ** > > > > > **** > > I think one interesting approach is to return events from your aggregates > instead of publishing them as described by this blog<http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/> > .**** > > ** ** > > Regards,**** > > /Johan**** > > ** ** > > 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? > >**** > > ** ** > > > > > **** > > **** > > >