2016-10-30 3 views
1

Итак, я узнал из блога о CQRS, что вы никогда не позволяли создавать свои сущности из воздуха. Вместо этого вы позволяете им создавать другой агрегат/объект.Как правильно получить объект и все его события из хранилища/хранилища?

Так, например, событие UserRegistered не связано с идентификатором зарегистрированного пользователя, но с идентификатором лица, зарегистрировавшего нового пользователя (например, Visitor), является ли это правильным?

Если я прав, у меня возникает проблема. Что делать, если теперь я хочу выполнить новое действие для пользователя. Я узнал из сообщений в блоге, что вы должны получить пользовательский объект из репозитория по id (который в основном представляет собой пустой объект в этой точке), и вы получаете историю событий из хранилища событий с использованием одного и того же идентификатора, а затем вы выполните историю событий на этом объекте, чтобы обновить ее, а затем попытайтесь выполнить новое действие.

Но это самое первое событие, событие, которое создало пользовательский объект в первую очередь, не было сохранено с идентификатором пользователя, поэтому я не получаю это событие. Я мог только вернуть это событие, выяснив, какой другой объект создал пользователя, а затем мне нужно сначала выполнить это действие для этого объекта. Но я не вижу способа узнать, какой объект создал пользователь. Поэтому я предполагаю, что у меня просто непонимание системы. Так что я пропущу?

ответ

1

Итак, я узнал из блога о CQRS, что вы никогда не позволяете создавать свои сущности из воздуха. Вместо этого вы позволяете им создавать другой агрегат/объект.

Это не относится к CQRS - это общее замечание относительно правильного моделирования домена. Ссылка: Udi Dahan Don't Create Aggregate Roots.

Так, например, UserRegistered событие не связано с идентификатором пользователя, который был только зарегистрирован, но с идентификатором объекта, который зарегистрирован новый пользователь (например, посетителей), это правильно?

Нет. Правильнее сказать, что событие UserRegistered должно быть связано с идентификаторами обоих объектов.

Так что же мне не хватает?

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 не изменилось.

+0

Так вы говорите, что это событие должно быть сохранено в истории пользователя? Как первое событие? Но тогда, как вы применяете это событие, когда вы повторно запускаете историю?Я имею в виду, что метод 'apply (UserCreatedEvent)' обычно находится на объекте пользователя? Но вы можете вызвать его только после того, как вы его создали. Или вы делаете метод apply() статическим методом? Таким образом, вы можете использовать его без/до создания экземпляра пользователя? – Evert

+0

Я думаю, вы меня немного поняли. Ваш ответ связан с состоянием всего приложения. Но я просто говорю о состоянии одной сущности, изолированной. Я узнал, что для того, чтобы обновить сущность, вы не перепрограммируете все события всего приложения. Вместо этого вы можете просто перезапустить все события для этого объекта. И затем я задаюсь вопросом, как вы заново запустили это первое событие, которое создало сущность. Потому что, если метод 'apply()' является методом для объекта, то вы можете применить метод EntityCreatedEvent только после того, как вы создали экземпляр объекта. Вы видите, почему я застрял там? – Evert

0

Я создаю проект с открытым исходным кодом, где у меня есть некоторые практические примеры того, как организация событий работает на практике для создания событий и регидратации модели. Взгляните, может быть, это поможет вам понять немного лучше концепцию.

https://github.com/politrons/Scalaydrated

Смежные вопросы