CQRS With Axon Tutorial: Part 6 – Build the Summary Projection

In this part we would create the summary projection class.This class would be part of the query package.

This is would be a spring bean (annotated with @Component annotation) and would be responsible for handle persistence. So it would be able to saved data. Also, it should retrieve data from the database to be displayed on the grid in the GUI.

 

Follow the 14 steps given below:

Step 1: Create a java class in the query package. Name it SummaryProjection

Step 2: Annotate the class with the @Component annotation

Step 3: Add a final private variable of type EntityManager

Step 4: Add a constructor and inject the EntityManager variable

The code for step 3 and 4 is shown below

 

private final EntityManager entityManager;

public SummaryProjection(EntityManager entityManager) {
    this.entityManager = entityManager;
}

 

Step 5: Create event handlers for the IssuedEvent() and RedeemedEvent()

Step 6: Create Query handler to return a list of card summaries

Step 7: Create a Query handler for handling the SizeQuery

 

At this point, the four methods will be as shown below:

@EventHandler
public void handle(IssuedEvent evt) {

}

@EventHandler
public void handle(RedeemedEvent evt) {

}

@QueryHandler
public List<CardSummary> handle(DataQuery query){

}

@QueryHandler
public Integer handle(SizeQuery query) {

}

 

Step 8: For the IssuedEvent, you need to create and persist a new entity. The code is shown below:

entityManager.persist(new CardSummary(
        evt.getId(),
        evt.getAmount(),
        evt.getAmount()
));

 

Step 9: For the RedeemedEvent, you need to first find the CardSummary and then update it’s balance. The code is shown below

CardSummary summary = entityManager.find(CardSummary.class,
        evt.getId());
summary.setRemainingBalance(summary.getRemainingBalance()
-evt.getAmount());

 

Step 10: Configure TrackingEventProcessor. You do this by creating an empty config method. It takes EventProcessingConfiguration as parameter.

Step 11: Annotate this method with @Autowired annotation

The code is given below:

//Configure Tracking Event
@Autowired
public void config(EventProcessingConfiguration config) {
    
}

 

Step 12: For the List QueryHandler, you need to create a query that returns a List<CardSummary> using the create() query method of the entityManager. The code is given below:

return entityManager
       .createQuery("SELECT c FROM CardSummary c ORDER BY c.id",
               CardSummary.class)
        .getResultList();

 

Step 13: For the QueryHandler for SizeQuery,  it would be similar to step 12. But this time write a query to return count..See code below

return entityManager
        .createQuery("SELECT COUNT(c) FROM CardSummary c",
                Long.class)
        .getSingleResult()
        .intValue();

 

At this point we are done with the summary projection and now we need to worry about getting the data into the grid in the GUI.

Step 14: Run the application. Also start the axonserver. Test to make sure everything works fine.

 

Just for review, I’m putting the complete code for the SummaryProjection class below. However, I recommend you type it out by yourself. In that way you improve your skills in CQRS with AxonFramework.

 

@Component
public class SummaryProjection {

    private final EntityManager entityManager;

    public SummaryProjection(EntityManager entityManager) {

        this.entityManager = entityManager;
    }

    @EventHandler
    public void on(IssuedEvt evt) {
        entityManager.persist(new CardSummary(
                evt.getId(),
                evt.getAmount(),
                evt.getAmount()
        ));
    }

    @EventHandler
    public void on(RedeemedEvt evt) {
        CardSummary summary = entityManager.find(CardSummary.class,
                evt.getId());
        summary.setRemainingBalance(summary.getRemainingBalance()
        - evt.getAmount());
    }

    //Configuring tracking event processor
    @Autowired
    public void config(EventProcessingConfiguration config) {
       // config.eventProcessor(getClass().getPackage().getName());
    }

    @QueryHandler
    public List<CardSummary> handle(DataQuery query) {
        return entityManager
                .createQuery("SELECT c FROM CardSummary c ORDER BY c.id",
                        CardSummary.class)
                .getResultList();
    }

    @QueryHandler
    public Integer handle(SizeQuery query) {
        return entityManager
                .createQuery("SELECT COUNT(c) FROM CardSummary c",
                        Long.class)
                .getSingleResult()
                .intValue();
    }
}