2016-01-30 12 views
3

Мы используем CQRS с EventSourcing.Как бороться с командой, которая зависит от существующих записей в приложении с использованием CQRS и источника событий

В нашем приложении мы можем добавлять ресурсы (это бизнес-термин для одного элемента) из ui, и мы отправляем команду соответственно для добавления ресурсов.

Итак, у нас есть x количество ресурсов, присутствующих в приложении, которые были добавлены ранее. Теперь у нас есть один специальный тип ресурса (я называю его как SpecialResource). Когда мы добавляем этот SpecialResource, идентификатор должен быть связан со всеми существующими ресурсами в приложении. Связанный означает, что у этого SpecialResource должен быть список ids (guids) (List) существующих ресурсов.

Решение, с помощью которого мы попытались получить все идентификаторы ресурсов в applcation перед добавлением специального ресурса (т. Е. Перед запуском команды AddSpecialResource). Назначьте эти списки SpecialResource, а затем отправьте команду AddSpecialResource.

Но мы не должны этого делать, потому что в соответствии с командой cqrs не следует запрашивать. I.e. команда can not зависит от запроса, поскольку запрос может иметь устаревшие записи.

Как мы можем достичь этого бизнес-сценария без запроса существующих записей в приложении?

+0

Вам действительно нужно материализовать список существующих ресурсов? Не может ли это предоставить база данных? (Кроме того, я не понимаю, зачем связывать «со всеми существующими ресурсами в приложении» - может быть, с выбором существующих ресурсов?) –

+0

В базе данных есть все ресурсы. Вы имеете в виду, что мы должны связывать все эти ресурсы в базе данных, а не в домене. Если мы это сделаем, укажите (в stateStore) SpecialResource не будут иметь идентификаторы ресурсов –

+0

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

ответ

1

Но мы не предполагаем делать это, потому что, как за команду CQ не должен запрашивать. То есть команда can not зависит от запроса, поскольку запрос может иметь устаревшие записи.

Это не совсем верно.

«Команды» постоянно запускают запросы. Если вы используете источник событий, в большинстве случаев ваши команды : запросов - «если эта команда разрешена, какие события будут сгенерированы?»

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

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

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

Хорошая новость: это, вероятно, не ваше настоящее требование. Подумайте, что вы описали до сих пор - если resourceId: 99652 создается за миллисекунду до SpecialResource, тогда он должен быть включен в состояние SpecialResource, но если он создается через миллисекунду после, то это не должно. Итак, . Какова стоимость для бизнеса, если ресурс создан за миллисекунду до того, как пропущен SpecialResource?

Потому что, априори, это не похоже на что-то, что должно быть слишком дорого.

Как правило, реальное требование выглядит чем-то более похожим: «SpecialResource должен включать все идентификаторы ресурсов, созданные до закрытия бизнеса», но вам фактически не нужен SpecialResource до 5 минут после закрытия бизнеса. Другими словами, у вас есть SLA здесь, и вы можете использовать этот SLA, чтобы лучше сообщить свою команду.

Как мы можем достичь этого бизнес-сценария без запроса существующих записей в приложении?

Включите его; запустите запрос, скопируйте результаты запроса (идентификаторы ресурсов) в команду, которая создает SpecialResource, затем отправьте команду, которая будет передана вашей модели домена. Команда CreateSpecialResource включает в себя правильный список идентификаторов ресурсов, поэтому агрегировать не нужно беспокоиться о том, как обнаружить эту информацию.

0

Трудно сказать, на что способна ваша база данных, но наиболее последовательный способ добавления «моментального снимка» находится на уровне базы данных, потому что для этого нет чистого места в чистых CQRS. (Есть некоторые статьи о выполнении снимков CQRS + ES, если это то, что вы на самом деле пытаетесь достичь с помощью SpecialResource).

Одним из способов может быть реализация списка идентификаторов с использованием какой-либо хранимой процедуры с приходом команды AddSpecialResource (в базе данных).

Другой способ - захватить «все существующие ресурсы (до момента)» с помощью какого-либо маркера (временную метку), никогда не удалять старые ресурсы и добавлять условия «SpecialResource» в запросах, которые будут использовать данные SpecialResource.

Хорошо, еще один вариант (в зависимости от вашего случая) - всегда иметь список идентификаторов, удобный с тем же запросом, который обслуживал пользовательский интерфейс. Таким образом, определение «всех ресурсов» изменяется на «все ресурсы, которые видит пользователь (в какой-то момент)».

+0

Да, в настоящее время мы используем последний подход, который вы предложили запросить перед отправкой команды. Но вы не думаете, что это нарушает CQRS, то есть «команда не должна запрашивать». –

+0

Это не о нарушении, это больше о том, что более логично/более последовательно в вашем случае. Скажем, когда специальный объект является списком сотрудников, приглашенным, имеет ли смысл, чтобы HR-клерк контролировал список или просто слепо «добавлял все», не увидев, что другой клерк только что добавил нового сотрудника? –

+0

В моем случае мне нужны все сотрудники, даже если это не видно на текущем экране (может быть, другой клерк только что добавил новую emp) –

0

Я не думаю, что никакая компьютерная система никогда не будет на 100% последовательной просто потому, что жизнь не работает и не может работать так. По-видимому, мы все также живем в прошлом, так как для вашего мозга требуется время для обработки ввода.

Дело в том, что вы делаете все возможное, используя имеющуюся информацию, но убедитесь, что ваша система способна сгладить любые края. Поэтому, если вам нужно связать один или два ресурса с вашим SpecialResource, тогда вы сможете это сделать.

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

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

Я надеюсь, что я не извращают свой вопрос :)

0

Вы можете сделать две вещи для того, чтобы решить эту проблему:

  • провести различие между чтения и записи модели. Вы знаете, что такое модель для чтения, не так ли? Таким образом, «написать модель» данных в противоположность - комбинация структур данных и поведения, которых достаточно, чтобы обеспечить соблюдение всех инвариантов и генерировать согласованные события (события) в результате каждой выполненной команды.

  • не принимает правило, в котором говорится, что «Магазин событий - это единственный источник истины» слишком буквально. Рассмотрим следующую интерпретацию: ES является единственным источником ВСЕЙ истины для вашего приложения, однако для каждой конкретной команды вы можете создавать «модели записи», которые обеспечат достаточно «правду», чтобы сделать эту команду последовательной.

+0

У нас есть отдельная модель для чтения и записи. Как вы сказали, «написать модель» данных в противоположность - это комбинация структур данных и поведения, которых достаточно, чтобы обеспечить соблюдение всех инвариантов и генерировать согласованные события (события). Проблема, которую я обнаружил при таком подходе, - это хранить данные всех объектов в статической структуре данных, и когда приложение будет отключено, все данные будут потеряны. например, для обеспечения уникального ограничения на имена сотрудников, мы добавляем каждое имя сотрудника EmplyeeNameList в каждую команду AddEmployee. Когда приложение не работает, мы потеряем все имена emp из этого списка. –

+0

Если мы сохраним нашу модель записи (модель данных) в качестве списка всех сотрудников, тогда в этом случае у нас будет только один entityId (Agg. Root) в контексте Bounded, который будет постоянным, и у каждого Emp не будет своего объекта entityId –

+0

. m не уверен, почему вы собираетесь его потерять, если вы храните эти данные в базе данных. – IlliakaillI