2015-07-13 2 views
10

EventSourcing отлично работает, когда у нас есть уникальный уникальный EntityID, но когда я пытаюсь получить информацию от eventStore, отличного от определенного EntityId, у меня тяжелое время.CQRS Event Sourcing проверить имя пользователя уникально или нет из EventStore при отправке команды

Я использую CQRS с EventSourcing. В рамках поиска событий мы сохраняем события в таблице SQL в виде столбцов (EntityID (uniqueKey), EventType, EventObject (например, UserAdded)).

Таким образом, сохраняя EventObject, мы просто сериализуем объект DotNet и сохраняем его в SQL. Таким образом, все данные, связанные с событием UserAdded, будут в формате xml. Меня беспокоит, что я хочу убедиться, что имя пользователя, которое присутствует в db, должно быть уникальным.

Итак, при выполнении команды AddUser мне нужно запросить EventStore (sql db), существует ли конкретное имя пользователя уже в eventStore. Так что для этого мне нужно сериализовать все события UserAdded/UserEdited в хранилище событий и проверить, присутствует ли запрашиваемое имя пользователя в eventStore.

Но как часть команд CQRS не разрешается запрашивать, может быть из-за состояния гонки.

Итак, я попытался перед отправкой команды AddUser просто запросить eventStore и получить все USERNAMES от сериализации все события (UserAdded) и получать имена пользователей и, если требуется имя пользователя является уникальным, то снимать команду еще бросать исключение, имя_пользователя уже существует ,

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

Ищу для любого лучшего подхода/предложения для поддержания пользователя Unique либо получить все имена пользователей из eventStore или любого другого подход

+1

Как сказал в своем ответе @Matt, используйте указатель рода на стороне команды/записи. Вы можете использовать что-то общее (не смотрели на NEventStore, поэтому я не знаю, есть ли у него что-то подобное): у меня есть интерфейс 'IKeyStore' в эксперименте: https://github.com/Shuttle/shuttle-recall- core/blob/master/Shuttle.Recall.Core/IKeyStore.cs, и вы можете увидеть и реализовать здесь: https://github.com/Shuttle/shuttle-recall-sqlserver/blob/master/Shuttle.Recall.SqlServer/KeyStore .cs --- Хэш произвольного ключа связан с AR id. Надеюсь, что это поможет :) –

ответ

10

Таким образом, ваш клиент (вещь, которая выдает команду) должен иметь полную веру что отправленная им команда будет выполнена, и она должна сделать это, убедившись, что перед отправкой RegisterUserCommand не будет зарегистрирован ни один другой пользователь с этим адресом электронной почты. Другими словами, ваш клиент должен выполнить проверку, а не ваш домен или даже приложения, окружающие домен.

От http://cqrs.nu/Faq

Это общераспространенный вопрос, так как мы явно не выполнения кросса-агрегатные операций на стороне записи. Тем не менее, у нас есть :

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

Создайте реактивную сагу, чтобы помечать и инактивировать учетные записи, которые были , тем не менее созданные с дублированным именем пользователя. (Будь то по крайней совпадению или злонамеренно или из-за неисправного клиента.)

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

+10

Последний параграф - это прагматическое решение. – MikeSW

+2

Последний вариант невозможен, если сторона записи является хранилищем событий. –

+1

@AlexeyZimarev. Ничто не мешает вам реализовать частную модель чтения, которая существует исключительно для модели записи, которая не является хранилищем событий. – Matt

3

Как часто, нет правильного ответа, только ответы, которые соответствуют вашему домену.

Вы находитесь в среде, которая действительно требует непосредственной согласованности? Каковы были бы шансы идентичного имени пользователя, создаваемого между уникальностью момента, проверяется путем запроса (скажем, на стороне клиента) и когда команда обрабатывается? Могут ли ваши эксперты домена терпеть, например, один из 1 миллиона конфликтов имен пользователей (что может быть компенсировано впоследствии)? У вас будет миллион пользователей в первую очередь?

Даже если требуется немедленная согласованность, «имена пользователей должны быть уникальными» ... в какой области? A Company? OnlineStore? A GameServerInstance? Можете ли вы найти наиболее ограниченную область, в которой должно быть ограничено единственность, и сделать эту область Агрегированным корнем, из которой будет прорастать нового пользователя? Почему «повторить все события с добавлением пользователей/пользователей» было бы плохо, если бы Агрегированный корень делал эти события малыми и простыми?

+0

Привет @ guillaume31, был бы способ связаться с вами за пределами SO? Вы выглядите довольно находчиво, и есть несколько проблем моделирования, которые я хотел бы обсудить с вами, если вы не возражаете? – plalx

+0

@ guillaume31 Да, требуется немедленная согласованность. –

+0

@ guillaume31 Да, требуется немедленная согласованность. Имя пользователя должно быть уникальным в области приложения. Почему все-таки «повторное использование всех событий с добавленным пользователем/UserEdited-событиями» будет плохой, если Aggregate Root делает эти события малыми и простыми? Ans: Согласно проверке уникальности имени пользователя мне нужны все существующие имена пользователей. В eventstore у нас будут lacs событий. Итак, мне нужно воспроизвести все события для всех EntityId (независимо от моего текущего EntityId). и для повторного воспроизведения все могут иметь влияние на производительность. Есть ли другой способ доступа ко всем текущим активным пользователям? –

1

С помощью GetEventStore (от Грега Янга) вы можете использовать любую строку как ваш aggregateId/StreamId. Используйте имя пользователя как идентификатор агрегата, а не гида, или комбинацию типа «mycompany.users.john» в качестве ключа и .. voila! У вас есть уникальная уникальность имени пользователя!

+0

Что делать, если бизнес требует, чтобы имя пользователя позволяло изменять? – Moim

+0

@Moim. Вы создаете другую категорию потока: «mycompany.usernames». В этой категории вы сохраняете потоки имен пользователей, такие как «mycompany.usernames-john» и сохраняете события привязки имени пользователя, например «UserId 1234 теперь ограничено именем пользователя« john », и другое событие, подобное «UserId 1234», больше не ограничено именем пользователя «john», и теперь имя пользователя «john» можно свободно принимать – Narvalex