【问题标题】:Multi-entity Aggregates command handling多实体聚合命令处理
【发布时间】:2019-05-29 21:21:33
【问题描述】:

我有一个这样的聚合根:

聚合根:

@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


【解决方案1】:

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

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

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

上面的一部分,我在查看您的 sn-ps 时还有其他一些建议,我想与您分享:

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

希望这可以帮助你@juggernaut!

【讨论】:

  • 谢谢史蒂文,这很有帮助。此代码仍处于开发的初始阶段,因此注意功能完整。您提出了一些很棒的建议,我一定会考虑并更新。
  • 关于 Aggregate not found 错误,securityUpdate 中的 ID 字段是成员中的 EntityId 聚合的 id,而不是 AggregateIdentitier。由于我希望将此更新应用于所有成员聚合并且没有 HopAggregate 的聚合标识符,我该如何进行这项工作?
  • 要将命令定向到聚合根中的聚合成员,您需要了解对该聚合根的外部引用,即聚合标识符。因此,框架无法知道如何路由仅包含聚合成员标识符的命令,您必须以某种方式添加聚合标识符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多