DDD и получение дополнительной информации в доменном классе
Я думаю, что прочитал 16 154 вопросов, постов в блогах, твитов и т. Д. О DDD и лучших практиках. Извиняюсь за еще один вопрос такого типа. Допустим, у меня есть три таблицы в моей базе данных: пользователь, отдел и пользовательский отдел. Все очень просто. Мне нужно построить иерархию, показывающую, к каким отделам пользователь имеет доступ. Проблема в том, что мне также нужно показать родительские отделы тех, к которым у них есть доступ.
Лучше ли иметь метод GetDepartments() в моем классе пользователя? Сейчас у меня есть пользовательский сервис с GetDepartments (строка userName), но я не думаю, что это оптимальное решение. Если предпочтительнее user.GetDepartments(), то как мне получить доступ к хранилищу, чтобы получить родительские отделы для тех, к которым у пользователя есть доступ?
Не думаю, что это имеет значение, но я использую Entity Framework.
public class User
{
[Key]
public int UserId { get; private set; }
[Display(Name = "User Name")]
public string UserName { get; private set; }
[Display(Name = "Email")]
public string Email { get; private set; }
[Display(Name = "UserDepartments")]
public virtual ICollection<UserDepartment> UserDepartments { get; private set; }
public List<Department> GetDepartments()
{
// Should this be here? and if so, what's the preferred method for accessing the repository?
}
}
1 ответ
DDD больше относится к поведению, что также означает, что оно ориентировано на TDA (скажите, не спрашивайте).
Обычно вы структурируете свои агрегаты таким образом, что вы говорите им, что делать, а не запрашиваете информацию.
Более того, если агрегату требуется какая-то дополнительная информация для того, чтобы выполнить его поведение, он, как правило, не должен выяснять, откуда получить эту информацию.
Теперь, когда вы говорите, что ваш пользовательский агрегат имеет метод GetDepartments, он поднимает сигнал. Нужна ли агрегату эта информация для выполнения какого-либо поведения? Я так не думаю, просто вы хотите, чтобы некоторые данные отображались.
Итак, я вижу, что вы пытаетесь структурировать свои агрегаты по таблицам данных, а не по поведению. Это на самом деле ошибка №2 при применении DDD (№ 1 не думает об ограниченных контекстах).
Опять же, агрегаты представляют бизнес-логику и поведение вашей системы. Это означает, что вам не нужно читать из агрегатов. Ваша сторона чтения может быть сделана намного проще - просто сделайте проклятый запрос к БД.
Но как только вам нужно попросить вашу систему сделать что-то - теперь вы делаете это с помощью агрегатов: AppService загрузит один из репозитория и вызовет его метод поведения.
Вот почему обычно у вас нет свойств в ваших агрегатах, только методы, которые представляют поведение.
Кроме того, вы все равно не хотите, чтобы ваши агрегаты отображались в таблицы данных, это не их работа, а работа репозиториев. На самом деле, вы не хотите, чтобы ваш домен зависел ни от чего, особенно от инфраструктуры.
Так что, если вы хотите пойти в направлении DDD, подумайте о следующем:
- Структурируйте свои агрегаты, чтобы инкапсулировать поведение, а не представлять таблицы данных
- Не делайте свой домен зависимым от инфраструктуры и т. Д.
- Сделайте репозитории ответственными за загрузку / сохранение агрегатов. Сами агрегаты не должны ничего знать о постоянстве, структуре данных и т. Д.
- Вам не нужно читать данные через агрегаты.
Представьте себе, что #4 - ваша система имеет две стороны: сторону "чтения", когда вы просто читаете данные и отображаете их в пользовательском интерфейсе, и сторону "команды", когда вы выполняете действия.
Первый (читай) очень прост: глупые запросы для чтения данных так, как вы хотите. Это ни на что не влияет, потому что это просто чтение, никаких побочных эффектов здесь.
Второй - когда вы вносите изменения, и это происходит через ваш домен.
Опять же, помните первое правило DDD: если у вас нет бизнес-логики и поведения для моделирования, не делайте DDD.