2

免責事項: 私はイベント ソーシング、Axon フレームワーク、および DDD にまったく慣れていないため、何か間違ったことをしている可能性が非常に高いです。

会議、ワークショップなどのイベントを管理するためのアプリケーションを実行しています。

EventProposal という集約ルートが 1 つあります。特定の EventProposal に TodoList を割り当てる可能性があるはずです。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);
    }

対応する success-path コマンドとイベント:

@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 を作成できる必要があります。Template は、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 をどこかで生成し、今後の TodoListFulfilledWithTemplateEvent に含めますか? これにより、1 つのイベントに 2 つのコレクションが含まれることになります。1 つは ID 用、もう 1 つはアイテムのコンテンツ/説明用です。
  • これらの ID を以前に生成し、それらを今後のイベントだけでなく、着信コマンドにも含めるとします。これは前と同じ醜さにつながりますが、2 倍になります。
  • 「assingTodoItemToTodoList」メソッドを複数回呼び出す方法で実行します。これにより、多くのイベントが生成され、イベントが非同期であるため、並べ替えが発生する可能性があります。

冗長で申し訳ありませんが、できるだけ具体的にしようとしました。

4

0 に答える 0