Axon 多实体聚合命令处理

Axon 多实体聚合命令处理,axon,Axon,我有这样一个聚合根: @EventHandler public void handleSecurityEvent(SecurityUpdate securityUpdate) { log.info("got security event {}", securityUpdate); commandGateway.send(securityUpdate); } 聚合根: @NoArgsConstructor @Aggregate(repository = "positionAggregateRep

我有这样一个聚合根:

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

@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.modeling.Command.AggregateNotFoundException(在事件存储中找不到聚合)

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


感谢您的帮助。

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

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

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

以上是我的一部分,在阅读您的代码片段时,我还有一些其他建议,我想与您分享:

  • @Aggregate
    @AggregateRoot
    进行元注释。因此,不需要在聚合类上同时指定这两个属性
  • 对于正在处理的日志消息,您可以利用
    LoggingInterceptor
    。您可以在任何能够处理消息的组件上对此进行配置,从而提供一种通用的日志记录方式。这将省略在消息处理函数中添加日志行的必要性
  • 您正在create和update命令上发布一个
    HopEvent
    。这样做会使您的
    HopEvent
    非常通用。理想情况下,您的事件会澄清系统中发生的业务操作。我的经验法则通常是这样的:“如果我告诉我的业务经理/客户事件类,他/她应该确切地知道它的作用”。因此,我建议将该活动更名为更具体的活动
  • HopEvent
    一样,
    UpdateHopCommand
    非常通用。命令应表示在应用程序中执行操作的意图。用户通常不希望更新,例如,他们希望更改地址。您的命令类理想地反映了这一点
  • 建议的命令命名约定是以现在时的动词开头。因此,它不应该是
    SecurityUpdate
    ,而应该是
    UpdateSecurity
    。命令是表示意图的请求,消息理想地反映了这一点

希望这对你有帮助@juggernaut

是否有一种方法可以将事件应用于所有聚合?谢谢Steven,这非常有用。此代码仍处于开发的初始阶段,因此在功能上是完整的。您提出了一些很好的建议,我将予以考虑并对此进行更新。关于Aggregate not found错误,securityUpdate中的ID字段是成员Aggregate中的EntityId,而不是AggregateIdentitier中的EntityId。由于我希望将此更新应用于所有memberaggregates,并且没有用于HopAggregate的aggregateIdentifier,因此如何使此更新生效?对于要定向到聚合根中的聚合成员的命令,您需要了解作为聚合标识符的该聚合根的外部引用。因此,框架无法知道如何路由只包含聚合成员标识符的命令,您必须以某种方式添加聚合标识符。