General question on updating Entity maps within aggregates

I have an an aggregate which extends AbstractEventSourcedAggregateRoot, called ConsumerDetail. In that root class have a Map of PaymentMethods that will be empty when the Consumer is created, but updated later with an AddPaymentMethodCommand. In the handler for the AddPaymentsMethodCommand, I load the consumer from the repo and update the payment method. However, next time I load the ConsumerDetail, there is nothing in that Map. I’m getting this message in the logs. Does anyone know what it means?

[] Ignoring aggregate registration. An aggregate of same type and identifier was already registered in this Unit Of Work: type [ConsumerDetail], identifier [0b1f5d69-8e7f-4b62-ae4d-49d7333fd2ee]

I’ve tried a number of things, but I can’t get entries into the Map with my event. Here is the code in the aggregate related to this process.

public class ConsumerDetail extends AbstractEventSourcedAggregateRoot {
private static final long serialVersionUID = 1L;

private static Logger log = LoggerFactory.getLogger(ConsumerDetail.class);

@AggregateIdentifier
private String id;
private String email;
private String firstName;
private String lastName;

@EventSourcedMember
private Map<String, PaymentMethod> paymentMethods = new HashMap<String, PaymentMethod>();


@CommandHandler
public void handle(RegisterCreditCardPaymentMethodCommand cmd) {
log.debug(“In the command handler for RegisterCreditCardPaymentMethodCommand”);
CreditCardPaymentMethod ccPaymentMethod = new CreditCardPaymentMethod(cmd.getId(), cmd.getConsumerId(), cmd.getCreatedTs(), cmd.isDefaultMethod(),
cmd.getPan(), cmd.getType(), cmd.getExpirationMonth(), cmd.getExpirationYear(), cmd.getCvv(), cmd.getBillingAddress());
ConsumerDetail consumer = repo.load(cmd.getConsumerId());
this.paymentMethods = consumer.getPaymentMethods();
this.paymentMethods.put(cmd.getId(), ccPaymentMethod);
consumer.setPaymentMethods(this.paymentMethods);
log.debug(“Consumer after update of paymentMethods {}”, consumer);
if (paymentMethods.containsKey(cmd.getId())) {
apply(new CreditCardPaymentMethodUpdatedEvent(cmd.getConsumerId(), cmd.getId(), ccPaymentMethod));
} else {
apply(new CreditCardPaymentMethodAddedEvent(cmd.getConsumerId(), cmd.getId(), ccPaymentMethod));
}

}

Hi,

the reason the map isn’t updated, is because you’re adding information to it in the command handler method. When an aggregate is loaded, it is constructed from events. Therefore, you should update the map inside an @EventSourcingHandler method. The general rule is: @CommandHandler methods do validation and decision making, @EventSourcingHandler methods do state changes.

If you use the Axon Test Fixtures to test your aggregate, it will detect and report these problems.

Hope this helps.
Cheers,

Allard

Hi Allard,

Thanks for the prompt reply. I have moved the update of the map to the event handler and have it working fine. I’m very new to Axon, so I appreciate the help

Carol