2

免责声明:我对事件溯源、Axon 框架和 DDD 完全陌生,所以我做错了什么的可能性很大。

我正在做一个应用程序来管理事件 - 会议、研讨会等。

我有一个聚合根,即 EventProposal。应该有可能将 TodoList 分配给给定的 EventProposal。TodoList 是另一个聚合根,由 TodoItems - 实体组成。TodoItem 可以编辑,标记为完成等。

需要将 TodoItem 分配给 TodoList,我是这样实现的:

public class TodoList extends AbstractAnnotatedAggregateRoot {
    @AggregateIdentifier
    private TodoListId id;

    @EventSourcedMember
    private List<TodoItem> todoItems = Lists.newArrayList();

    ...

    public void assignTodoItem(TodoItemId todoItemId, String content, LocalDate creationDate) {

        if (alreadyHasTodoItemWith(todoItemId)) {
            apply(new TodoItemNotAssignedToTodoList(
                            id, todoItemId)
            );

            return;
        }

        apply(new TodoItemAssignedToTodoListEvent(
                        id, todoItemId, content, creationDate)
        );
    }

    @EventSourcingHandler
    public void on(TodoItemAssignedToTodoListEvent event) {
        final TodoItem item = TodoItemFactory.create(
                event.todoItemId(),
                event.description(),
                event.createdAt()
        );

        todoItems.add(item);
    }

对应的成功路径命令和事件:

@Value
@Accessors(fluent = true)
public class AssignTodoItemToTodoListCommand {

    @TargetAggregateIdentifier
    private final TodoListId todoListId;
    private final TodoItemId todoItemId;
    private final String description;
    private final LocalDate createdAt;

}



@Value
@Accessors(fluent = true)
public class TodoItemAssignedToTodoListEvent {

    private final TodoListId todoListId;
    private final TodoItemId todoItemId;
    private final String description;
    private final LocalDate createdAt;

}

这可以通过 Axon 的 BDD 方式轻松测试。(GivenThenFixture)

但是现在 - 还有另一个要求:应该能够在现有的 TodoListTemplate 上创建 TodoList。模板只是包装了 TodoItemTemplates 集合的聚合。

我的实现问题出现了。我尝试了类似的东西(在 TodoList 类中):

public void fulfillWith(TodoListTemplate todoListTemplate, LocalDate creationDate) {
    if (alreadyHasAnyTodoItem()) {
        apply(new TodoListNotFulfilledWithTemplateEvent(
                        id,
                        todoListTemplate.id()
                )
        );
        return;
    }

    apply(new TodoListFulfilledWithTemplateEvent(
                    id,
                    todoListTemplate.id(),
                    todoListTemplate.todoItemDescriptions(),
                    creationDate
            )
    );
}

@EventSourcingHandler
public void on(TodoListFulfilledWithTemplateEvent event) {
    todoItems.addAll(
        fromDescriptions(event.todoItemDescriptions(), event.fulfilledAt())
    );
}

private Collection<TodoItem> fromDescriptions(Collection<String> descriptions, LocalDate creationDate) {
    return descriptions.stream()
            .map(description -> TodoItemFactory.create(description, creationDate))
            .collect(Collectors.toList());
}

同样,命令和事件:

@Value
@Accessors(fluent = true)
public class FulfillTodoListWithTemplateCommand {

    private final TodoListId todoListId;
    private final TodoListTemplateId todoListTemplateId;
    private final LocalDate creationDate;

}

@Value
@Accessors(fluent = true)
public class TodoListFulfilledWithTemplateEvent {

    private final TodoListId todoListId;
    private final TodoListTemplateId todoListTemplateId;
    private final List<String> todoItemDescriptions;
    private final LocalDate fulfilledAt;
}

问题:如您所见 -TodoItemFactory涉及类,生成唯一 ID:

public static TodoItem create(String content, LocalDate createdAt) {
        return TodoItemFactory.create(nextId(), content, createdAt);
}

这样它就不能用轴突测试——它给了我错误org.axonframework.test.AxonAssertionError: Illegal state change detected! 这很明显——工作聚合的 ID 与应用事件后构造的 ID 不同。

最后,我的问题来了:

我应该如何解决这个问题?

  • 在某处生成这些 ID 并将它们包含在输出的 TodoListFulfilledWithTemplateEvent 中?这导致在一个事件中有两个集合 - 一个用于 ID,一个用于项目内容/描述。
  • 假设我得到了之前生成的那些 ID,并且不仅将它们包含在输出事件中,而且还包含在传入命令中。这导致与以前相同的丑陋,但两次。
  • 以我多次调用“assingTodoItemToTodoList”方法的方式执行此操作,这将生成大量事件并可能产生重新排序,因为事件是异步的。

抱歉冗长,我试图尽可能具体。

4

0 回答 0