多实体聚合命令处理

Multi-entity Aggregates command handling

我有一个这样的聚合根:

聚合根:

@NoArgsConstructor
@Aggregate(repository = "positionAggregateRepository")
@AggregateRoot
@XSlf4j
@Data
public class HopAggregate {

@AggregateIdentifier
private String hopId;
private FilteredPosition position;
private LocalDate positionDate;
@AggregateMember
private Security security;

@CommandHandler
public HopAggregate(NewHopCommand cmd) {
    log.info("creating new position , {}", cmd.getDateId());
    apply(new HopEvent(cmd.getHopId(), cmd.getDateId(), cmd.getFilteredPosition(), cmd.getSecurity(), false));
}

@CommandHandler
public void handle(UpdateHopCommand cmd) {
    log.info("creating hop update event {}", cmd);
    apply(new HopEvent(this.hopId, this.positionDate, cmd.getFilteredPosition(), this.security, true));
}

@CommandHandler
public void handle(SecurityUpdate cmd) {
    log.info("updating security {}", cmd);
    apply(new SecurityUpdateEvent(this.hopId, cmd.getFilteredSecurity()));
}

@EventSourcingHandler
public void on(HopEvent evt) {
    if (evt.getIsUpdate()) {
        log.info("updating position {}", evt);
        this.position = evt.getFilteredPosition();
    } else {
        log.info("adding new position to date {}", evt);
        this.hopId = evt.getHopId();
        this.positionDate = evt.getDate();
        this.position = evt.getFilteredPosition();
        this.security= evt.getSecurity();
    }
}

@EventSourcingHandler
public void on(SecurityUpdateEvent evt) {
    log.info("hop id {}, security update {}", this.hopId, evt.getFilteredSecurity().getSecurityId());
}

}

子实体:

@XSlf4j
@Data
@RequiredArgsConstructor
@NoArgsConstructor
public class IpaSecurity implements Serializable {

@EntityId
@NonNull
private String id;
@NonNull
private FilteredSecurity security;
}

我的问题是,当我像这样推送和更新时:

@EventHandler
public void handleSecurityEvent(SecurityUpdate securityUpdate) {
log.info("got security event {}", securityUpdate);
commandGateway.send(securityUpdate);
}

我的命令是:

@Data
@RequiredArgsConstructor
@NoArgsConstructor
@ToString
public class SecurityUpdate {

@NonNull
@TargetAggregateIdentifier
private String id;
@NonNull
private FilteredSecurity filteredSecurity;
}

我收到聚合根未找到异常:

命令 'com.hb.apps.ipa.events.SecurityUpdate' 导致 org.axonframework.modelling.command.AggregateNotFoundException(在事件存储中找不到聚合)

我不确定如何处理这种情况。我的要求是每个聚合都应检查它是否包含安全性,然后在发出命令时更新它。我错过了什么?如果您需要有关代码的更多信息,请告诉我。

感谢您的帮助。

命令总是针对单个实体。 该实体可以是聚合、包含在聚合中的实体(Axon 框架称为聚合成员)或简单的单例组件。 不过需要注意的是,只有一个 实体处理命令。

这就是要求您在命令中设置 @TargetAggregateIdentifier 的原因,以便 Axon 能够将其路由到单个聚合实例(如果有问题的命令处理程序是其中的一部分)。

您收到的 AggregateNotFoundException 信号表明您的 SecurityUpdate 命令中的 @TargetAggregateIdentifier 注释字段不对应于任何现有聚合。 因此,我怀疑 SecurityUpdate 中的 id 字段与 HopAggregate 聚合中的任何 @AggregateIdentifier 注释字段不对应。

根据以上内容,我在查看您的代码片段时还有其他一些建议想与您分享:

  • @Aggregate 是 meta-annotated 和 @AggregateRoot。因此,您不需要在聚合 class
  • 上指定两者
  • 对于正在处理的日志消息,您可以使用 LoggingInterceptor。您可以在任何能够处理消息的组件上配置它,从而提供一种通用的日志记录方式。这将省略在消息处理函数中添加日志行的必要性
  • 您正在对创建和更新命令发布 HopEvent。这样做会使您的 HopEvent 非常通用。理想情况下,您的事件会阐明系统中发生的业务操作。我的经验法则通常是这样的:"If I tell my business manager/customer about the event class, he/she should know exactly what it does"。因此,我建议将事件重命名为更具体的名称
  • HopEvent 一样,UpdateHopCommand 非常通用。您的命令应该表达在您的应用程序中执行操作的意图。用户通常不希望更新,例如,他们希望更改地址。您的命令 classes 完美地反映了这一点
  • 建议的命令命名约定是以现在时的动词开头。因此,它不应该是 SecurityUpdate,而是 UpdateSecurity。命令是表达意图的请求,消息理想地反映了这一点

希望这对你有帮助 @juggernaut!