Это нормально для сущностей для доступа к репозиториям? - PullRequest
25 голосов
/ 06 мая 2009

Я только начал работать с 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?

Спасибо, P

Ответы [ 5 ]

23 голосов
/ 06 мая 2009

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

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

Поэтому, когда вам нужен объект Person, вы переходите к personRepository.GetPersonWithDefaultEmployer () и возвращаете сотрудника, в котором по умолчанию есть работодатель. PersonRepository будет зависеть от EmployerRepository и будет использовать ее для заполнения лица перед его возвратом.

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;
    }
}
5 голосов
/ 22 марта 2011

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

Как правило, никогда не делайте этого. Держите свои сущности без ссылок на репозитории. [ надеть практическую шапку ] В некоторых редких, очень редких случаях, когда у вас есть очень, очень, очень веская причина для этого, чем добавить большой комментарий, объясняющий, почему вы это делаете и делаете - добавьте ссылку или используйте Double Dispatch для передачи хранилища [ hat off ]

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

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

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

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

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

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

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

3 голосов
/ 11 августа 2013

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

0 голосов
/ 10 августа 2013

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

0 голосов
/ 20 марта 2011

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

А что, если у вас нет хранилища в памяти, а есть реляционная база данных для вашего хранилища, и вы хотите получить 1000 человек с их работодателем? Собираетесь ли вы сделать 1000 запросов с помощью вызова EmployerRepository ...?

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

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

...