Сущности домена, имеющие доступ к репозиториям

Продолжая эти дебаты:

DDD - правило, согласно которому сущности не могут напрямую обращаться к репозиториям

Допускается ли доступ сущностей к репозиториям?

По-прежнему существуют ситуации, когда Домену удобнее получить доступ к репозиторию. Возьмем этот пример, который предполагает, что мне нужна таблица TaskStatus в базе данных, которая содержит описание для целей отчетности:

public class TaskStatus
{
    public long Id {get;set;}
    public string Description {get;set;}
}

public class Task
{
    public long Id {get;set;}
    public string Description {get;set;}
    public TaskStatus Status {get;set;}

    public void CompleteTask()
    {
        ITaskStatusReposity repository = ObjectFactory.GetInstace<ITaskStatusReposity>(); //Or whatever DI you do.
        Status = repository.LoadById(Constants.CompletedTaskStatusId);
    }
}

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

И вообще, почему интерфейсы репозитория хранятся в Домене, если не для такого рода вещей?


person Paul T Davies    schedule 04.07.2011    source источник


Ответы (1)


Могут ли сущности получать доступ к репозиториям?

Нет, пожалуйста, не делай этого.

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

Домен не должен знать о сохранении данных и должен предполагать, что это происходит автоматически.

ddd-the-repository-pattern. aspx

Во-вторых, есть и другие более практичные причины не внедрять свои репозитории в свои enties.

  1. Ваши объекты должны быть доступны для модульного тестирования, путем внедрения ваших репозиториев в вашу сущность, которую вы создали в зависимости от вашего репозитория.

  2. Использование метода GetInstance () нарушает закон Деметры, вы создаете тесную связь ITaskStatusRepository с вашей сущностью. Это означает, что при создании новой задачи и написании модульных тестов не очевидно, что для задачи требуется ITaskStatusRepository. Это затрудняет модульное тестирование вашей бизнес-логики.

  3. С точки зрения DDD, репозиторий не только связан с взаимодействием с БД, но и может быть получен из хранилища в памяти. Или список.

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

  5. Ваши сущности не должны беспокоиться о выполнении действий с базой данных.

См. Изображение, размещенное здесь:

DDD: как следует организовать слои?

public class TaskStatus
{
   public long Id { get; set; }
   public string Description { get; set; }

   public TaskStatus() {
      Description = "Incomplete";
   }
}

public class Task
{
    public long Id {get;set;}
    public string Description {get;set;}
    public TaskStatus Status {get;set;}

    public void CompleteTask()
    {        
        Status.Description = "Complete";
    }
}

Внутри уровня приложения ваш репозиторий отвечает за сохранение (или нет). Репозиторий - это Список ‹> совокупных корней. И это работает на общем корневом уровне.

Пример использования ваших Задач внутри TaskService. Служба воздействует на сущности на уровне вашего приложения.

public class TaskService 
{
    private readonly ITaskRepository _taskRepository;

    public TaskService(ItaskRepository taskRepository){
      _taskRepository = taskRepository;
    }

    public List<Task> CompleteAllTasks()
    {
      List<Tasks> getTasks = _taskRepository.GetTasks();
      getTasks.ForEach(CompleteTask);
      return _taskRepository.Save(getTasks);
    }    
}
person Justin Shield    schedule 04.07.2011
comment
1 + 2: получая доступ к ITaskStatusRepository, домен не знает о природе стойкости, хотя я согласен, что он знает о существовании стойкости. Конечно, это все еще можно тестировать, потому что репозиторий можно смоделировать? Я все еще не уверен, как вы предлагаете мне достичь того, что я пытаюсь сделать выше? - person Paul T Davies; 04.07.2011
comment
3: Я не уверен, что еще делает мой репозиторий, кроме доступа к базе данных? 4: Хорошо, поэтому TaskStatus может быть перечислением, и у вас может быть что-то вроде 'public void Complete () {Status = TaskStatus.Complete; } 'и StatusDescription должны быть свойством Task? - person Paul T Davies; 04.07.2011
comment
Если я не ошибаюсь, я действительно не согласен с тем, что «CompleteTask» - это то, что принадлежит репозиторию. Мой пример очень тривиальный, и единственная бизнес-логика состоит в том, что когда задача завершена, ее статус меняется на «выполнено». Эта логика могла бы быть намного сложнее и, конечно, не должна выполняться в репозитории? - person Paul T Davies; 04.07.2011
comment
ddd-the-repository-pattern ‹- Репозиторий не должен фактически использоваться объектами домена. Репозиторий представляет собой Список ‹› агрегированных корней. Репозиторий может отвечать или не отвечать за сохраняемость. Таким образом, ваше действие Complete Task вообще не должно внедрять репозиторий. Он должен просто обновить статус задачи напрямую. Я обновлю ответ. - person Justin Shield; 04.07.2011
comment
С вашим новым редактированием я больше не могу получить доступ к описанию TaskStatus из Задачи? - person Paul T Davies; 04.07.2011
comment
Я снова отредактировал вопрос, извините за это. Эффективное полное удаление репозитория из сущностей. Вера в то, что в репозитории будет сохранен агрегированный корень. - person Justin Shield; 04.07.2011