Итак, я узнал из блога о CQRS, что вы никогда не позволяете создавать свои сущности из воздуха. Вместо этого вы позволяете им создавать другой агрегат/объект.
Это не относится к CQRS - это общее замечание относительно правильного моделирования домена. Ссылка: Udi Dahan Don't Create Aggregate Roots.
Так, например, UserRegistered событие не связано с идентификатором пользователя, который был только зарегистрирован, но с идентификатором объекта, который зарегистрирован новый пользователь (например, посетителей), это правильно?
Нет. Правильнее сказать, что событие UserRegistered должно быть связано с идентификаторами обоих объектов.
Так что же мне не хватает?
ddd
Event Sourcing действительно использует термин repository
, но этот термин заимствован из домена Driven Design. Вы можете читать агрегаты и агрегировать корни, но для вашего конкретного конфликта ответ заключается в том, что в мире с источниками событий репозиторий загружает историю и создает сущность из этой истории. История должна включать все события, необходимые для построения этой истории.
Если в вашей модели, User
и Visitor
являются транзакционно отдельными понятиями, и у вас есть UserRegistered
события, которое ссылается на них обоих, должно быть сохранены в истории объекта, который изменил событие.
Хотя эта история не существовала до тех пор, пока пользователь не был зарегистрирован. Шаблоны создания странные.
Значит, вы говорите, что событие должно быть сохранено в истории пользователя? Как первое событие?
Да, точно.
Я имею в виду, что метод apply (UserCreatedEvent) обычно имеет право на пользовательский объект? Но вы можете вызвать его только после того, как вы его создали.
Просмотрите, что может сказать Грег Янг о Functional Domain Models. Но основная идея заключается в том, что вы делаете левый сгиб
state[n+1] = state[n].apply(event)
И ваш вопрос по существу ветры это обратно «что вызвало первую причину?»
State currentState = ...?
events.each (e -> currentState = currentState.apply(e))
Для вновь созданных объектов, мое предложение заключается в том, что вы начинаете срок службы всех объектов из общего SEED государства. Но вы так же легко перенести первое событие в истории на конструктор вместо того, чтобы применять его к семени.
как вы можете повторить это первое событие, которое создало объект. Потому что, если метод apply() является методом объекта, то вы можете применить EntityCreatedEvent только после того, как вы создали экземпляр объекта. Вы видите, почему я застрял там?
Да - вы путаете Entity с состояния субъекта.
class Bob implements Entity<Bob> {
class State implements Value<Seed> {
State apply(Event e) {...}
static State SEED = new State(...);
// ...
}
class Factory implements Factory<Bob> {
Bob rebuild(Iterable<Event> history) {
return rebuild(State.SEED, history);
}
Bob rebuild(State currentState, Iterable<Event> history) {
for(Event e : history) {
currentState = currentState.apply(e);
}
return create(currentState);
}
Bob rebuild(State currentState) {
return new Bob(currentState);
}
}
}
Это длинная форма написания того, что происходит. Эта более простая версия также «прекрасна».
Bob rebuild(Iterable<Event> history) {
Bob target = new Bob();
for(Event e : history) {
target.apply(e);
}
return target;
}
Или даже
Bob rebuild(Iterable<Event> history) {
return new Bob(history);
}
Одна возможность состоит в том, что вы смущены о том, где UserRegistered
событие происходит из - так как он описывает изменение состояния User
, а не Visitor
, она должна быть считается частью модуля User
.
Большинство команд, которые вы читаете из репозитория, вносит некоторые изменения, а затем сохраняете результат в том же репозитории. Но создание weird; вы читаете состояние от VisitorRepository
, но записываете состояние в UserRepository
- потому что Visitor
не изменилось.
Так вы говорите, что это событие должно быть сохранено в истории пользователя? Как первое событие? Но тогда, как вы применяете это событие, когда вы повторно запускаете историю?Я имею в виду, что метод 'apply (UserCreatedEvent)' обычно находится на объекте пользователя? Но вы можете вызвать его только после того, как вы его создали. Или вы делаете метод apply() статическим методом? Таким образом, вы можете использовать его без/до создания экземпляра пользователя? – Evert
Я думаю, вы меня немного поняли. Ваш ответ связан с состоянием всего приложения. Но я просто говорю о состоянии одной сущности, изолированной. Я узнал, что для того, чтобы обновить сущность, вы не перепрограммируете все события всего приложения. Вместо этого вы можете просто перезапустить все события для этого объекта. И затем я задаюсь вопросом, как вы заново запустили это первое событие, которое создало сущность. Потому что, если метод 'apply()' является методом для объекта, то вы можете применить метод EntityCreatedEvent только после того, как вы создали экземпляр объекта. Вы видите, почему я застрял там? – Evert