@AggregateIdentifier & @TargetAggregateIdentifier 的理解

Understanding of @AggregateIdentifier & @TargetAggregateIdentifier

所以我正在学习轴突框架,只是想巩固我对 @TargetAggregateIdentifier 注释的理解。

我的命令:

public class IssueCardCommand {

private String cardId;
private String versionNumber;
private Integer amount;

@TargetAggregateIdentifier
private String getAggregateIdentifier() {
    return (null != versionNumber) ? cardId + "V" + versionNumber : cardId;
    }
}

我的汇总:

@Aggregate
@Slf4j
public class GiftCard {

private String giftCardId;
private String versionNumber;
private Integer amount;

@AggregateIdentifier
private String getAggregateIdentifier() {
    return (null != versionNumber) ? giftCardId + "V" + versionNumber : giftCardId;
}

public GiftCard() {
    log.info("empty noargs constructor");
}

@CommandHandler
public GiftCard(IssueCardCommand cmd) {
    log.info("handling {}",cmd);
    //this.giftCardId = cmd.getCardId();
    //this.versionNumber = cmd.getVersionNumber();
    apply(new CardIssuedEvent(cmd.getCardId(),cmd.getVersionNumber(),cmd.getAmount()));
}

@EventSourcingHandler
public void onCardIssuedEvent(CardIssuedEvent evt) {
    log.info("applying {}",evt);
    this.giftCardId = evt.getCardId();
    this.versionNumber = evt.getVersionNumber();
    this.amount = evt.getAmount();
    }
}

所以这一切都按预期工作并且事件被正确存储。但是,我只是想确保我正确理解了@TargetAggregateIdentifier 和@AggregateIdentifier 注释。

所以,

@TargetAggregateIdentifier - 命令转到聚合的特定实例,因此需要告诉框架它是哪个实例,因此 field/method 上的注释用于加载该实例的事件特定聚合?

我注意到当构造函数的命令中没有@TargetAggregateIdentifier 时,代码仍然有效。但是如果它在任何后续命令中丢失,它会给出错误 'Invalid command, It does not identify the target aggregate',我觉得这证实了我上面的理解?

@AggregateIdentifier - 这告诉轴突框架这是标识符,以便在引入更多命令时它需要存储该特定聚合的事件?

如果有人能指出我的理解是否正确并在不正确的地方发表评论,我将不胜感激,以便我可以以正确的方式使用该框架。

谢谢。

我已经在最初发布问题的 AxonIQ 讨论平台上提供了 answer

因为用 link 回答只会违反 SO 的礼仪,所以我也在这里应对我的回答:

Your understanding is correct I guess. But let me give you a simplified explanation of the process so you can compare it to your current understanding.

When you issue a command that creates new aggregate (one that is handled by the Aggregate's constructor) there is no need for identifier. The reason is you are creating a new instance, not loading an existing one. In that case the framework only needs the FQCN of the aggregate in order to create an instance of it. It can easily find the FQCN because it knows (from inspection during aggregate registration) which aggregate can handle such create command. That's why create commands without @TargetAggregateIdentifier work just fine.

Once the create command is processed the aggregate's state needs to be stored somewhere.

  • for event sourced aggregates all state changing events are stored in a event store
  • for state stored aggregates the entire state is stored in a repository

In both cases the framework needs to know how to identify this data. That's what @AggregateIdentifier is for. It tells the framework to store the data in way that it is identifiable by specific identifier. You can think of it as primary key in DB terms.

When you send a command to an existing instance of an aggregate you need to tell which instance that is. You do so by providing a @TargetAggregateIdentifier . The framework will then create a new empty instance of the respective aggregate and then try to load the data into it

  • for event sourced aggregates by reading all the past events related to that instance
  • for state stored aggregates by reading current state from a repository

In both cases the framework will search for data that's identifiable by the value of @TargetAggregateIdentifier. Once the aggregate data is loaded it will proceed with handling the command.