Hi, if we are talking about projection/view, so the term @Aggregate is not pretty accurate, and could potentially lead into confusion.
You can then have two different approaches: the first one is to implement the concept of Stored-State Aggregate (you can read more in the ref-guide https://docs.axoniq.io/reference-guide/axon-framework/axon-framework-commands/modeling/state-stored-aggregates)
Second approach is to define a @Component, that will handle all the @EventHandler of his interest and update the view model using a JpaRepository. You can find an example of this into https://github.com/AxonIQ/hotel-demo/blob/master/booking/src/main/java/io/axoniq/demo/hotel/booking/query/AccountHandler.java
A clear drawbacks of the first approach is that data are stored in the projection with the form of the aggregate, as-is you will define it. Any change to your aggregate will be reflected in the query/view side.
Introducing a clear separation of concern between command and query, as the second approach suggest, will give you a lot of degrees of freedom into your query side: it is not rare to define more than one projection that is sourced from events that belongs to one aggregate.
You can then define a @ProcessingGroup : this will give you the possibility to introduce a method into your projection annotated with @ResetHandler that will be in charge to delete all the data from the repository. This method can be triggered calling the method resetTokens() on the specific EventProcessor . More info in the ref-guide https://docs.axoniq.io/reference-guide/axon-framework/events/event-processors#replaying-events
Sayed so : I suggest to introduce an actuator endpoint into your application that can be safely called to trigger a reset on a certain eventProcessor
Below you can find an example of code.
import org.axonframework.config.Configuration;
import org.axonframework.eventhandling.TrackingEventProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.lang.invoke.MethodHandles;
@Component
@Endpoint(id="scheduletokenreset")
public class TriggerResetEventEndpoint {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final Configuration configuration;
public TriggerResetEventEndpoint(Configuration configuration) {
this.configuration = configuration;
}
@DeleteOperation()
public void triggerResetEventEndpointFor(String processingGroup) {
Assert.hasLength(processingGroup, "Processing Group is mandatory and can't be empty!");
logger.info("Trigger ResetTriggeredEvent for processingGroup {}", processingGroup);
configuration.eventProcessingConfiguration()
.eventProcessorByProcessingGroup(processingGroup,
TrackingEventProcessor.class)
.ifPresent(trackingEventProcessor -> {
trackingEventProcessor.shutDown();
trackingEventProcessor.resetTokens();
trackingEventProcessor.start();
});
}
}
Another simpler approach is to set to 0 the value of token into the token_entry table created on your client side for a certain processor_name : please note that this should be done after all client application are shut down. You will also need to take care to drop manually data created into your projection triggered by the specific processor.
Although this is simpler contains a lot of pitfall and I strongly suggest to do not use this approach in a production environment.