0
votes

Environment setup : Axon 4.4, H2Database( we are doing component testing as part of the CI) Code looks something like this.

    @Aggregate(repository = "ARepository")
    @Entity
    @DynamicUpdate
    @Table(name = "A")
    @Getter
    @Setter
    @NoArgsConstructor
    @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
    @Log4j2
    Class A implements Serializable {
    
    
      @CommandHandler
      public void handle(final Command1 c1) {
        apply(EventBuilder.buildEvent(c1));
      }
    
      @EventSourcingHandler
      public void on(final Event1 e1) {
      //some updates to the modela
        apply(new Event2());
      }
    
      @Id
      @AggregateIdentifier
      @EntityId
      @Column(name = "id", length = 40, nullable = false)
      private String id;
    
       @OneToMany(
          cascade = CascadeType.ALL,
          fetch = FetchType.LAZY,
          orphanRemoval = true,
          targetEntity = B.class,
          mappedBy = "id")
      @AggregateMember(eventForwardingMode = ForwardMatchingInstances.class)
      @JsonIgnoreProperties("id")
      private List<C> transactions = new ArrayList<>();
    }
    
    @Entity
    @Table(name = "B")
    @DynamicUpdate
    @Getter
    @Setter
    @NoArgsConstructor
    @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
    @Log4j2
    Class B implements Serializable {
    
      @Id
      @EntityId
      @Column(name = "id", nullable = false)
      @AggregateIdentifier
      private String id;
    
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumns({@JoinColumn(name = "id", referencedColumnName = "id")})
      @JsonIgnoreProperties("transactions")
      private A a;
    
      @EventSourcingHandler
      public void on(final Event2 e2) {
       //some updates to the model
      }
    }

I'm using a state store aggregate but I keep getting the error randomly during Spring Test with embedded H2. The same issue does not occur with a PGSQL DB in non embedded mode but than we are not capable of runnign it in the pipeline.

Error : "java.lang.IllegalStateException: The aggregate identifier has not been set. It must be set at the latest when applying the creation event"

I stepped through AnnotatedAggregate

    protected <P> EventMessage<P> createMessage(P payload, MetaData metaData) {
            if (lastKnownSequence != null) {
                String type = inspector.declaredType(rootType())
                                       .orElse(rootType().getSimpleName());
                long seq = lastKnownSequence + 1;
                String id = identifierAsString();
                if (id == null) {
                    Assert.state(seq == 0,
                                 () -> "The aggregate identifier has not been set. It must be set at the latest when applying the creation event");
                    return new LazyIdentifierDomainEventMessage<>(type, seq, payload, metaData);
                }
                return new GenericDomainEventMessage<>(type, identifierAsString(), seq, payload, metaData);
            }
            return new GenericEventMessage<>(payload, metaData);
        }

The sequence for this gets set to 2 and hence it throws the exception instead of lazily initializing the aggregate

Whats the fix for this? Am i missing some configuration or needs a fix in Axon code?

2
Would you mind adding how you are using the test fixtures from Axon to test your aggregates? Expecting everything to be autowired in a non-spring focused Test Fixture is likely the culprit.Steven

2 Answers

0
votes

I believe the exception you are getting is the pointer to what you are missing @Rohitdev. When an aggregate is being created in Axon, it at the very least assume you will set the aggregate identifier. Thus, that you will fill in the @AggregateIdentifier annotated field present in your Aggregate.

This is a mandatory validation as without an Aggregate Identifier, you are essentially missing the external reference towards the Aggregate. Due to this, you would simply to be able to dispatch following commands to this Aggregate, as there is no means to route them.

From the code snippets you've shared, there is nothing which indicates that the @AggregateIdentifier annotated String id fields in Aggregate A or B are ever set. Not doing this in combination with using Axon's test fixtures will lead you the the exception you are getting.

When using a state-stored aggregate, know that you will change the state of the aggregate inside the command handler. This means that next to invoke in the AggregateLifecycle#apply(Object) method in your command handler, you will set the id to the desired aggregate identifier.

There are two main other pointers to share based on the question. There is no command handler inside your aggregate which creates the aggregate itself. You should either have an @CommandHandler annotated constructor in your aggregates, or use the @CreationPolicy annotation to define a regular method as the creation point of the aggregate (as mentioned here in the reference guide).

Lastly, your sample still uses @EventSourcingHandler annotated functions, which should be used when you have an Event Sourced Aggregate. It sounds like you have made a conscious decision against Event Sourcing, hence I wouldn't use those annotations either in your model. Right now it will likely only confuse developers that a mix of state-stored and event sourced aggregate logic is being used.

0
votes

Finally after debugging we found out that in class B we were not setting the id for update event

@EventSourcingHandler
 public void on(final Event2 e2) {
    this.id=e2.getId();
 }

Once we did that the issue went away.