Входные параметры репозитория DDD

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

var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetById(user.CustomRoleId);

or

var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetForUser(user);

person Robert    schedule 25.08.2016    source источник
comment
для чего загружаются пользователь и его роль?   -  person tomliversidge    schedule 25.08.2016
comment
@tomliversidge Чтобы создать токен авторизации и получить разрешения роли, чтобы привязать его к этому токену   -  person Robert    schedule 25.08.2016


Ответы (3)


Учитывая два варианта, я бы, вероятно, выбрал первый, который обеспечивает согласованность доступа по идентификатору.

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

Это предполагает, что вы правильно смоделировали свои агрегаты... :)

person tomliversidge    schedule 25.08.2016
comment
Что-то вроде CQRS? - person Robert; 25.08.2016
comment
Терминология может зависеть от того, с кем вы разговариваете :) Но я часто использую термин CQRS (Command Query Responsibility Segregation), когда есть отдельное хранилище данных для чтения, которое предварительно проецируется именно на модели чтения, требуемые ответами. Он асинхронно обновляется на основе потока событий. Однако другим не менее действенным методом является CQS (разделение командных запросов), когда у вас есть набор запросов, которые выполняют стандартные запросы к хранилищу сохраняемости модели записи. Запросы разделены в приложении, но модель чтения не полностью отделена. - person Chris Simon; 26.08.2016
comment
Поэтому для меня реализация запроса модели чтения, который просто соединяет таблицу Users с таблицей CustomRoles и возвращает dto модели чтения, будет CQS. Но также я думаю, что это хорошая идея, если данные идут прямо к данным ответа пользовательского интерфейса или API. Если вы собираетесь использовать возвращаемые данные для взаимодействия с агрегатами/сущностями предметной области, то, что вы делаете с репозиториями, лучше, потому что вы используете модели предметной области с моделями предметной области и сохраняете их стратегии доступа независимыми. - person Chris Simon; 26.08.2016
comment
Спасибо за объяснение разницы между CQS и CQRS. У меня всегда было впечатление, что это одно и то же. - person Robert; 26.08.2016

Не хочу этого говорить, но в среде DDD я бы не ответил ни тем, ни другим.

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

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

Но в обоих случаях приложению по-прежнему нужны два репозитория для получения информации. Что происходит, когда необходимо больше отношений? Количество репозиториев может быстро вырасти, и все превратится в беспорядок.

При проектировании, ориентированном на предметную область, вы должны попытаться мыслить в терминах совокупных корней (AR) и контекстов предметной области. В вашем примере контекста пользователь является AR, а роль становится дочерней. Итак, у вас может быть:

var user = _userFinder.GetById(1);
var customRole = user.CustomRole;

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

person Cerad    schedule 25.08.2016
comment
CustomRole представляет другой AggregateRoot в BC. У него есть свои объекты (разрешения) и т. д. Несколько пользователей могут использовать одну и ту же CustomRole. Что вы предлагаете, так это рассматривать CustomRole как объект значения, и когда CustomRole обновится, мне придется распространить это изменение на всех пользователей в этой роли? - person Robert; 25.08.2016
comment
Два арса в пределах одного и того же до н.э. звучат как проблема. В вашем примере я бы рассматривал роль как объект-значение. Я бы использовал другой bc для обновления роли и отправил бы уведомление, чтобы сообщить пользователям, что роль изменилась. Конечно, многое из этого зависит от того, действительно ли вам приходится иметь дело со сложной бизнес-логикой. Трудно давать конкретные рекомендации, не зная общей картины. - person Cerad; 25.08.2016
comment
Между прочим, я думаю, что на такие вопросы лучше отвечать на programmers.stackexchange.com. - person Cerad; 25.08.2016
comment
Я бы не стал заходить так далеко и говорить, что AgrRoots в одном и том же БК звучит как проблема. Вон Вернон в своей книге Implementing DD Design привел пример Identity and Access Context, и он имел 4 совокупных корня в контексте. У меня нет контекстов пользователей или ролей. У меня есть контекст, ограниченный личностью и разрешениями. IMO AR служит границей согласованности, а контекст описывает модель моей проблемы. - person Robert; 25.08.2016
comment
@Cerad Два ars в одном и том же bc звучат как проблема. Это абсолютно неверно. AR не являются субдоменами. В идеале должен быть один BC на поддомен, и весьма вероятно, что на BC будет несколько AR. Если все ваши BC имеют совокупные имена, значит, вы делаете это неправильно. BC являются автономными компонентами, но с этим разделением связаны затраты (например, наличие антикоррупционного уровня, конечная согласованность и т. д.). - person plalx; 27.08.2016

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

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

Если вы загружаете ById, я также обнаружил, что использование типизированных объектов-значений идентификаторов может быть весьма полезным для обеспечения дополнительного уровня безопасности типов - некоторые разговоры о плюсах и минусах здесь https://stackoverflow.com/a/5377460/6720449 и здесь https://groups.google.com/forum/#!topic/dddcqrs/WQ9zRtW3Gbg

person Chris Simon    schedule 25.08.2016