How does Axon get results of EventSourcingHandler?

Fair warning: I have no idea I’m doing, so even the asking of this question may go awry.

I’m wanting to update state on a simple object (the Aggregate) and then provide the UI with a projection of the changed object. Here’s my aggregate object (command handler exists, but not shown here).

@Aggregate
public class Widget {
@AggregateIdentifier
private String id;
private String color;

@EventSourcingHandler
public void on(ChangeColorEvt evt) {
color = evt.getColor();
}

}

…and here is my projection:

public class WidgetProjection {

private final EntityManager entityManager;

private final QueryUpdateEmitter queryUpdateEmitter;

@EventHandler

public void on(ChangeColorEvt evt) {

ProjectedWidget projection = entityManager.find(ProjectedWidget.class, evt.getId());

projection.setColor(evt.getColor());

queryUpdateEmitter.emit(FetchWidget.class, query -> evt.getId().startsWith(query.getFilter().getIdStartsWith()), projection);

}

}

The QueryHandler does what you would expect, finding the instance and returning it.

So here are my questions:

Why do I need the EventSourcingHandler in the Aggregate? That is, it appears to do work, but the result isn’t stored or sent anywhere.

So, that becomes my next question: After executing the EventSourcing Handler, is the resulting instance of Widget (not the projection) stored, seen, or sent anywhere?

If EventSourcingHandler is indeed needed, is there any way to avoid having two independent copies of my business logic (one in EventSourcingHandler, and one EventHandler)? I really hate the idea of having to update the same business logic in two places.

I appreciate any clarity the group can provide. Thanks for your help!

Jonathan

Why do I need the EventSourcingHandler in the Aggregate? That is, it appears to do work, but the result isn’t stored or sent anywhere.
You only need the eventsourcing handler if you need the state from an event in applying other business logic in another command handler on your aggregate

After executing the EventSourcing Handler, is the resulting instance of Widget (not the projection) stored, seen, or sent anywhere
No, using event sourcing your aggregate is rebuilt by replaying the events for the entity. A materialized view is never stored anywhere (except your projections as noted)

If EventSourcingHandler is indeed needed, is there any way to avoid having two independent copies of my business logic (one in EventSourcingHandler, and one EventHandler)?
EventSourcingHandlers don’t have business logic in them. All of your business logic needs to be applied in any CommandHandlers.

Does this help?

Ah, so the state changes in the EventSourcingHandlers (ESH) are only made to enable decision logic in the CommandHandlers (CH), right? And, if an ESH state change will not be used in a latter CH decision, the ESH could/should be eliminated, right? Instead, the state should only change in the EventHandler (EH) in the query, right?

Still, in a situation where an ESH is needed, the EH’s state change is basically identical to it. If the state change involves multiple properties with calculations, there is an opportunity for error: perhaps the calculations are coded correctly in the ESH, but not in the EH. We’ve created a bad situation because we have essentially the same calculations, but in two places. Is there a way to avoid that?

In the situation you suggest, I would try very hard to put those calculations in the aggregate and have the event contain these values. Remember, an event is something that has happened in the past. If you are still making calculations after the event has occurred, it starts to break the paradigm.

If that first option does not work for you, you could always move the calculations into another class that can be invoked in different locations.