Достаточно ли для объектов получить доступ к репозиториям?

Я только начал работать с DDD, так что, возможно, это глупый вопрос...

Можно ли получить доступ к репозиторию (через некоторый интерфейс IRepository) для получения значения во время выполнения? Например, я хочу принудительно выполнить выбор по умолчанию для свойства:

class Person {
    private Company _employer;

    public Company Employer {
        get { return _employer; }
        set { 
            if(value != null) {
                _employer = value;
            } else {
                _employer = employerRepository.GetDefaultEmployer();
            }
        }
    }

    ...
}

Мой вопрос заключается в том, что делать что-то подобное - это ужасное нарушение принципов DDD. И если это не так, моим следующим вопросом будет то, что это лучший способ предоставить репозиторий для использования? Должен ли он быть поставлен при создании объекта Person?

Спасибо, Р

Ответ 1

Это не ужасное нарушение DDD, это ужасное нарушение... ну... это просто ужасно (я говорю этот язык в щеку):).

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

Итак, когда вам нужен Человек, вы отправите personRepository.GetPersonWithDefaultEmployer() и вернете человека, у которого есть работодатель по умолчанию. PersonRepository будет иметь зависимость от работодателяRepository и использовать его для заполнения человека до его возвращения.

PersonReposotory : IPersonRepository
{
    private readonly IEmployerRepository employerRepository;

    //use constructor injection to populate the EmployerRepository
    public PersonRepository(IEmployerRepository employerRepository)
    {
        this.employerRepository = employerRepository;
    }

    public person GetPersonWithDefaultEmployer(int personId)
    {
        Person person = GetPerson(personId);
        person.Employer = employerRepository.GetDefaultEmployer(personId);
        return person;
    }
}

Ответ 2

Тип ответа на ваш вопрос является стандартным: Это зависит.

Как правило, никогда не делайте этого. Держите свои сущности без ссылок на репозитории.

[надевая практическую шляпу] В некоторых крайне редких случаях, когда у вас есть очень, очень, очень веская причина для этого, добавьте большой комментарий, объясняющий, почему вы это делаете, и сделайте это: добавьте ссылку или используйте Double Отправьте, чтобы передать хранилище [без шапки]

Кроме того, если вы хотите следовать принципам DDD, настоятельно рекомендуется иметь доступ к эксперту по предметной области и итеративному процессу разработки (см. Эрик Эванс - то, что я узнал со времени появления книги).

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

Несколько вещей относительно кода, который вы разместили:

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

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

  3. Вызывающий объект, устанавливающий значение Employer of Person (либо с помощью общедоступного установщика, либо с помощью общедоступного метода), должен знать точный экземпляр Company, который он хочет установить, даже если это экземпляр по умолчанию. Возможно, вызывающая сторона может иметь ссылку на хранилище.

  4. В зависимости от вашего конкретного домена, Компания может быть ценным объектом. В этом случае вместо инициализации _employer с нулевым значением вы можете инициализировать его значением по умолчанию для объекта значения. Это может быть в том случае, если у вас очень мало компаний (1-2), и они неизменны и не имеют определенного поведения.

Ответ 3

Я думаю, что легко сказать, что сущность не должна знать о репозиториях, но трудно применить ее на практике. Особенно, когда агрегат получает большую коллекцию vo внутри него, мы должны реорганизовать его и делегировать операции, такие как добавить в какую-либо службу домена, которая фактически действует как репозиторий, чтобы избежать накладных расходов на загрузку всей коллекции в память,
Но я не думаю, что разумно позволять сущности знать о репозиториях. Если нам нужно, используйте вместо этого службы домена. Мы также должны учитывать, нарушает ли репозиторий принцип Single Responsibility - его следует рассматривать как Коллекция совокупных корней, а не нормальная factory.

Ответ 4

Это действительно то, что рекомендуется делать ddd?

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

Я бы использовал NHibernate или любой ORM, чтобы помочь реализовать personRepository. В NHibernate я буду использовать Hibernate Query рядом с этим: "from Person join fetch Employer", который будет загружать экземпляр "Employer" в каждом экземпляре "Person" с одним SQL-запросом.

Это нарушение DDD?

Ответ 5

Прежде всего, я думаю, что сама сущность и как собрать сущность на самом деле являются 2 обязанностями. Поэтому в идеале лучше распределить их по разному классу. Но это тоже зависит.