Java 事件来源-将事件从AR传递给实体
我有一个更复杂的聚合根结构和事件源的问题。假设我有一段代码:Java 事件来源-将事件从AR传递给实体,java,events,domain-driven-design,cqrs,event-sourcing,Java,Events,Domain Driven Design,Cqrs,Event Sourcing,我有一个更复杂的聚合根结构和事件源的问题。假设我有一段代码: class AggregateRoot{ Entity entity1; Entity entity2; //this is returned to service layer to be persisted to db in event stream AggregateRootUpdatedState execCommand(int command){ entity1 = new E
class AggregateRoot{
Entity entity1;
Entity entity2;
//this is returned to service layer to be persisted to db in event stream
AggregateRootUpdatedState execCommand(int command){
entity1 = new Entity();
EntityUpdatedStateEvent event1 = this.entity1.changeState(command);
EntityUpdatedStateEvent event2 = null;
if(entity1.state==1) { //since we already set sub entity - we can check this
entity2 = new Entity();
event2 = this.entity2.changeState(command);
}
AggregateRootUpdatedState parentEvent = new AggregateRootUpdatedState(event1, event2);
//when(parentEvent); //??? WE ALREADY CHANGED STATE IN TWO LINES ABOVE
return parentEvent;
}
void when(AggregateRootUpdatedState event){ //needed for re-hydrating the event state
entity1 = new Entity();
entity1.when(event.event1);
if(event.event2!=null) {
entity2 = new Entity();
entity2.when(event.event2);
}
}
}
class Entity{
int state;
EntityUpdatedStateEvent changeState(int state){
EntityUpdatedStateEvent event = new EntityUpdatedStateEvent(state);
when(event);
return event;
}
void when(EntityUpdatedStateEvent event){
this.state = event.state;
}
}
class EntityUpdatedStateEvent{
int state;
EntityUpdatedStateEvent(int state) {
this.state = state;
}
}
class AggregateRootUpdatedState{
EntityUpdatedStateEvent event1; //here we are nesting events AR->Entity
EntityUpdatedStateEvent event2;
AggregateRootUpdatedState(EntityUpdatedStateEvent event1, EntityUpdatedStateEvent event2) {
this.event1 = event1;
this.event2 = event2;
}
}
如您所见,有一个聚合根AggregateRoot
,它有两个子实体entity1
和entity2
。当AR接收到命令(在本例中为simpleint command
)时,它必须调用子实体上的一些方法,以便它们修改其状态。作为对此的反应,它们触发EntityUpdatedStateEvent
,该事件通过调用when
方法自动应用于实体内部。此时应用事件可以保证当实体返回时,聚合根将具有正确的状态集,并且我将能够在聚合根中执行比较测试if(entity1.state==1)
。根据这个测试,我还更新了其他实体状态。然后,这两个事件被组合成AggregateRootUpdatedState
事件,并保存到事件存储中
现在,我的问题是-在AR中,当第一次发生AggregateRootUpdatedState
方法时(仅在重新水合AR时),我不会调用。既然我看到AR状态也应该通过调用when
方法来修改,那么这种方法正确吗
是否有其他方法将事件向下传递到AR层次结构
更新
class AggregateRoot{
List<SubEntityLevel1> subEntityLevel1s;
int rootNum;
void command(int x){
rootNum = x*x;
for(int i=0; i<x; i++){
SubEntityLevel1 subEntityLevel1 = new SubEntityLevel1();
subEntityLevel1.modify1(i, rootNum);
subEntityLevel1s.add(subEntityLevel1);
}
}
void when(AggregateRootModifiedEvent event){
//HOW TO REFACTOR METHOD ABOVE TO EVENT?
}
}
class SubEntityLevel1{
int id;
List<SubEntityLevel2> subEntityLevel2s;
int sum = 0;
void modify1(int id, int rootNum){
//HOW TO MAKE EVENT FROM THIS AND THEN APPLY IN WHEN() METHOD?
this.id = id;
this.sum = rootNum;
for(int i=0; i<id; i++){
if(subEntityLevel2s.stream().noneMatch(se2 -> "0".equals(se2.id))) {
SubEntityLevel2 subEntityLevel2 = new SubEntityLevel2();
subEntityLevel2.modify2(i);
subEntityLevel2s.add(subEntityLevel2);
sum++;
}
}
}
void when(SubEntityLevel1Modified event){
this.id = event.id;
this.sum = event.sum;
for(SubEntityLevel2Modified subEvent : event.subEntity2Events){
when(subEvent);
}
}
void when(SubEntityLevel2Modified event){
SubEntityLevel2 subEntityLevel2 = new SubEntityLevel2();
subEntityLevel2.when(event);
subEntityLevel2s.add(subEntityLevel2);
}
void when(SubEntityLevel2Created event){
//??????
}
}
class SubEntityLevel2{
String id;
SubEntityLevel2Modified modify2(int x){
SubEntityLevel2Modified event = new SubEntityLevel2Modified(String.valueOf(x));
when(event);
return event;
}
void when(SubEntityLevel2Modified event){
this.id = event.id;
}
}
//----- EVENTS
class AggregateRootModifiedEvent{
int rootNum;
List<SubEntityLevel1Modified> subEntity1Events;
public AggregateRootModifiedEvent(int rootNum, List<SubEntityLevel1Modified> subEntity1Events) {
this.rootNum = rootNum;
this.subEntity1Events = subEntity1Events;
}
}
class SubEntityLevel1Modified{
int id;
List<SubEntityLevel2Modified> subEntity2Events;
int sum;
public SubEntityLevel1Modified(int id, List<SubEntityLevel2Modified> subEntity2Events, int sum) {
this.id = id;
this.subEntity2Events = subEntity2Events;
this.sum = sum;
}
}
class SubEntityLevel2Created{}
class SubEntityLevel2Modified{
String id;
SubEntityLevel2Modified(String id){
this.id = id;
}
}
然后将这两个事件组合成AggregateRootUpdatedState事件,并保存到事件存储中
在我看来,这是一种反模式;您可以让它在模型的版本1中工作,但当您想要开始重构或响应事件时,它会引入大量额外的工作。您可能应该考虑返回事件集合,而不是单个单一事件
您的聚合代码将如下所示
History execCommand(int command){
entity1 = new Entity();
EntityUpdatedStateEvent event1 = this.entity1.changeState(command);
EntityUpdatedStateEvent event2 = null;
if(entity1.state==1) { //since we already set sub entity - we can check this
entity2 = new Entity();
event2 = this.entity2.changeState(command);
}
// ALL of the state changes have already happened, so no need to
// re-process the events.
return History.of(event1, event2)
}
另一件需要注意的事情是,在本例中,您一直在更改根实体而没有生成事件,特别是在创建子事件时
entity1 = new Entity();
为什么实体生命周期的开始在您的模型中不是一件明确的事情?应该有这样一个事件,确保实体引用(this.entity1,this.entity2)总是以相同的方式分配
EntityOneCreatedEvent createEntityOne() {
EntityOneCreatedEvent e = new EntityOneCreatedEvent();
when(e);
return e;
}
是否有其他方法将事件向下传递到AR层次结构
一种方法是使用Meyer模式,将创建事件的逻辑与更新实体状态的逻辑分开。
基本思想是,在查询中,您永远不会更改自己的状态(您可以复制您的状态,然后更改副本);在命令中,将更改应用于本地状态
如果您认为状态是一种不可变的值类型,那么这种模式真的会自然而然地从中产生。谢谢您的回复。你能检查一下我更新的问题吗,因为它现在更真实地反映了我的问题。我同意我应该有这个CreatedEvent(但是在我上面的新问题中,我不知道以后如何引用它)。另外,正如您在第一个代码段中所回答的,在第一次执行时,最终聚合根不需要应用事件,仅在重新水合时。有没有梅耶模式与事件来源相关的例子?我会看一看——不过,作为一个一般性的提示:任何时候你询问DDD,你都应该尽可能接近你真正的问题。具有泛型约束的泛型域很难智能地建模。
EntityOneCreatedEvent createEntityOne() {
EntityOneCreatedEvent e = new EntityOneCreatedEvent();
when(e);
return e;
}