Dear all,
I’m developing an application, which keeps dealers in PostgreSQL. My axon aggregate class uses an identifier, which is composed of dealers dispatch type and account number, which is a unique identifier defined by the business logic.
My app supports file import of dealers with the following logic:
- New dealers are inserted into db (CreateDealerCommand)
- Existing dealers are updated (UpdateDealerCommand)
- Dealers missing in the file are removed from the database (DeleteDealerCommand)
Unfortunately, I have an issue with the scenario, where the dealer is firstly created using CreateDealerCommand, then removed using DeleteDealerCommand and lastly created again using CreateDealerCommand.
The first two commands (CreateDealerCommand and DeleteDealerCommand) are successfully executed and two events are stored in db, both with identifier 03013712 and increasing sequence (0 and 1).
However, when I try to create the dealer with identifier 03013712 again, I’m not able to continue in the sequence and the app starts a new sequence.
`
org.axonframework.modelling.command.ConcurrencyException: An event for aggregate [03013712] at sequence [0] was already inserted
at org.axonframework.eventsourcing.eventstore.AbstractEventStorageEngine.handlePersistenceException(AbstractEventStorageEngine.java:123)
at org.axonframework.eventsourcing.eventstore.jpa.JpaEventStorageEngine.lambda$appendEvents$6(JpaEventStorageEngine.java:286)
at org.axonframework.common.transaction.TransactionManager.executeInTransaction(TransactionManager.java:47)
at org.axonframework.eventsourcing.eventstore.jpa.JpaEventStorageEngine.appendEvents(JpaEventStorageEngine.java:279)
at org.axonframework.eventsourcing.eventstore.AbstractEventStorageEngine.appendEvents(AbstractEventStorageEngine.java:98)
at org.axonframework.eventsourcing.eventstore.AbstractEventStore.prepareCommit(AbstractEventStore.java:63)
at org.axonframework.eventhandling.AbstractEventBus.doWithEvents(AbstractEventBus.java:218)
at org.axonframework.eventhandling.AbstractEventBus.lambda$null$8(AbstractEventBus.java:152)
at org.axonframework.messaging.unitofwork.MessageProcessingContext.notifyHandlers(MessageProcessingContext.java:71)
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.notifyHandlers(DefaultUnitOfWork.java:106)
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.changePhase(AbstractUnitOfWork.java:222)
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commitAsRoot(AbstractUnitOfWork.java:83)
at org.axonframework.messaging.unitofwork.AbstractUnitOfWork.commit(AbstractUnitOfWork.java:71)
at org.axonframework.messaging.unitofwork.DefaultUnitOfWork.executeWithResult(DefaultUnitOfWork.java:92)
at org.axonframework.commandhandling.SimpleCommandBus.handle(SimpleCommandBus.java:176)
at org.axonframework.commandhandling.AsynchronousCommandBus.lambda$handle$0(AsynchronousCommandBus.java:89)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1460)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1440)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308)
at com.sun.proxy.$Proxy158.flush(Unknown Source)
at org.axonframework.eventsourcing.eventstore.jpa.JpaEventStorageEngine.lambda$appendEvents$6(JpaEventStorageEngine.java:283)
… 17 common frames omitted
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3176)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3690)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
… 25 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint “domain_event_entry_uq_aggregate_sequence”
Detail: Key (aggregate_identifier, sequence_number)=(03013712, 0) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2183)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:308)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:120)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
… 33 common frames omitted
`
I have the following aggregate to handle my commands
@Aggregate
@NoArgsConstructor
public class DealerAggregate {
//dispatch type + account number
@AggregateIdentifier
private String composedCode;
@CommandHandler
public DealerAggregate(CreateDealerCommand cmd) {
apply(new DealerCreatedEvent(cmd.getMetadata(), cmd.getDealer()));
}
@CommandHandler
public void on(UpdateDealerCommand cmd){
apply(new DealerUpdatedEvent(cmd.getMetadata(), cmd.getDealer()));
}
@CommandHandler
public void on(DeleteDealerCommand cmd){
apply(new DealerDeletedEvent(cmd.getMetadata(), cmd.getDealer()));
}
@EventSourcingHandler
public void on(DealerCreatedEvent event) {
composedCode = event.getDealer().getDispatchTypeCode() + event.getDealer().getAccountNumber();
}
}
I tried to create a method like below, however, it’s never called.
`
@CommandHandler
public void on(CreateDealerCommand cmd){
apply(new DealerCreatedEvent(cmd.getMetadata(), cmd.getDealer()));
}
`
Do you please have any ideas on how to deal with this issue? I tried to create a new void method on(CreateDealerCommand) however, this method is never called.
Thank you in advance!
Best regards,
Jaroslav Schnaubert