无法使用Repository.load()为Integer AggregateIdentifier加载聚合



我一直在尝试使用存储库类的加载方法加载聚合,但没有成功。我知道load((方法需要一个字符串参数,但我的聚合标识符是integer。我已经尝试转换为字符串,但无法加载聚合。我一直都是空的。我的代码显示在下面

@Autowired
private Repository<Product> repository;
@CommandHandler
public Order(CreateOrderCommand cmd){
try{
//This line throws an error
Product product = (Product) repository.load(Integer.toString(cmd.getProductId()));
}
catch (Exception ex){
System.out.println("Oops! Error Occured: " + ex.getMessage());
}
apply(
new OrderCreatedEvent(
cmd.getOrderId(), cmd.getPrice(), cmd.getNumber(), cmd.getProductId()
)
);
}

我正在提供更多更新:我只是想在下新订单时更新产品库存。因此,我所做的是,在创建新订单的CommandHandler中,我只需找到Product聚合并调用它的UpdateStock方法,这是一个命令处理程序。有什么我真的不明白吗?

这些文件如下:产品汇总:

@Aggregate
public class Product {
@AggregateIdentifier
private String id;
private Double price;
private Integer stock;
private String description;
public Product() {
}
@CommandHandler
public Product(AddProductCommand cmd){
apply( new ProductAddedEvent(
cmd.getId(),
cmd.getPrice(),
cmd.getStock(),
cmd.getDescription()
)
);
}
@CommandHandler
public void updateStock (UpdateStockCommand cmd){
if(this.stock >= cmd.getStock()){
apply(new StockUpdatedEvent(cmd.getId(), cmd.getStock()));
}
else {
throw new RuntimeException("Out of Stock!");
}
}
@EventSourcingHandler
public void on(StockUpdatedEvent evt){
id = evt.getId();
stock = stock - evt.getStock();
}
@EventSourcingHandler
public void on(ProductAddedEvent evt){
id = evt.getId();
price = evt.getPrice();
stock = evt.getStock();
description = evt.getDescription();
}
}

订单汇总:

@Aggregate
public class Order {
@AggregateIdentifier
private String  orderId;
private Double price;
private Integer number;
private String productId;
//Repository provides an abstraction for storage of Aggregates
@Autowired
private Repository<Product> repository;
@CommandHandler
public Order(CreateOrderCommand cmd){
try{
//This line throws an error
Product product = (Product) repository.load(cmd.getProductId());
}
catch (Exception ex){
System.out.println("Oops! Error Occured: " + ex.getMessage());
}
apply(
new OrderCreatedEvent(
cmd.getOrderId(), cmd.getPrice(), cmd.getNumber(), cmd.getProductId()
)
);
}
@EventSourcingHandler
public void on(OrderCreatedEvent evt){
orderId = evt.getOrderId();
price = evt.getPrice();
number = evt.getNumber();
productId = evt.getProductId();
}
}
正如您所注意到的,Axon将为聚合标识符强制执行String。这并不意味着您需要直接提供String。只要您实现了一个合理的toString()方法,它就会非常好地工作。因此,使用Integer作为聚合标识符将导致该字段的toString()结果被用作聚合标识符。

话虽如此,我很惊讶您无法基于此加载聚合。也许我们需要在此基础上做一些跟进,但首先我想对你分享的片段发表评论。

似乎在Order类上有一个构造函数命令处理程序。此外,这向我表明Order类是一个集合。我想声明,决不建议从另一个聚合中加载一个聚合。

这样做会将Order聚合上的锁与Product聚合绑定在一起,从而阻塞系统中比CreateOrderCommand的发送方所期望的更大的部分。聚合之间的通信应通过事件消息始终保持异步。因此,这需要一个专用的事件处理组件,该组件根据发布的事件在两个实例之间进行协调。

因此,我强烈建议改写你在这件事上的逻辑。当谈到装载总量时,我现在很难给你一个理由。因此,让我提出几个后续问题。顺便说一下,我建议用回复更新你的原始请求;以保持良好的连续性。

你在用哪个版本的Axon?围绕Product聚合,您是否使用了任何有趣的配置?您是否将应用程序与Axon Server配对?如果是,标准版还是企业版?您是直接使用配置API还是使用axon-spring-boot-starter


更新

谢谢你更新你的问题,金德森,让我也更新我的答案。

首先,正如我之前所说,我永远不会从另一个聚合中加载一个聚合。您的Order类和Product类都是aggregate,这些片段过于清楚地表明您正在从Order聚合中合并"产品Repository"。

这种方法不仅会延长聚合上的锁,从而给用户带来压力,而且遵循这种方法可能会导致死锁。根据经验,始终遵循异步方法在聚合实例之间进行通信。因此,组件对聚合的事件作出反应,并将命令分派给另一个。这可以在常规事件处理组件或Saga中完成。

除此之外,我还在本地测试了是否可以使用Integer作为聚合标识符。因此,作为聚合中的@AggregateIdentifier注释字段,作为命令消息上的@TargetAggregateIdentifier注释字段。最重要的是,我通过让框架调用Repository#load(String)操作(因此只是在CommandGateway/CommandBus上调度一个命令(直接调用它来尝试这一点。

遗憾的是,这对我来说很好。因此,作为另一个后续行动,我建议分享你在执行Repository#load(String)操作时遇到的实际异常。

最新更新