我一直在尝试使用存储库类的加载方法加载聚合,但没有成功。我知道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();
}
}
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)
操作时遇到的实际异常。