DDD - Как реализовать высокопроизводительные репозитории для поиска - PullRequest
25 голосов
/ 20 января 2010

У меня есть вопрос относительно DDD и шаблона хранилища.

Допустим, у меня есть репозиторий Customer для совокупного корня Customer. Методы Get & Find возвращают полностью заполненный агрегат, который включает в себя такие объекты, как Address и т. Д. Все хорошо. Но когда пользователь ищет клиента в пользовательском интерфейсе, мне просто требуется «сводка» совокупности - просто плоский объект с обобщенной информацией.

Один из способов справиться с этим - вызвать метод find в репозитории как обычно, а затем на уровне приложения сопоставить каждый клиентский агрегат с DTO CustomerSearchResult / CustomerInfo и отправить их обратно клиенту.

Но моя проблема с этим - производительность; каждому клиентскому агрегату может потребоваться несколько запросов для заполнения всех ассоциаций. Так что, если мои критерии поиска соответствовали 50 клиентам, это довольно большой удар по БД для потенциального извлечения данных, которые мне даже не понадобятся.

Другая проблема заключается в том, что я могу включить сводные данные о клиенте, которые находятся за пределами общей корневой границы Клиента, например, дату последнего заказа. У заказа есть своя собственная совокупность, и поэтому, чтобы получить информацию о заказе клиента, я должен был бы вызвать OrderRepository, что также снижает производительность.

Так что теперь я думаю, что у меня есть два варианта:

  1. Добавить дополнительный метод Find в CustomerRepository, который возвращает список этих сводных объектов, выполняя один эффективный запрос.

  2. Создайте специально созданный для чтения только для клиента CustomerInfoRepository, в котором есть только метод поиска, описанный в 1.

Но оба они чувствуют, что я иду против принципов DDD. Мои репозитории наследуются от общей базы: Репозиторий, где T: IAggregateRoot. Эти объекты сводной информации не являются агрегатами и имеют тип, отличный от T, поэтому на самом деле # 1 идет вразрез с дизайном.

Возможно, для # 2 я бы создал абстрактный SearchRepository без ограничения IAggregateRoot?

В моем домене много похожих сценариев.

Как бы вы реализовали этот сценарий?

Спасибо, Dave

Обновление

После прочтения ответа Тео, я думаю, я перейду к варианту # 2 и создам специализированный SearchRepository в моей инфраструктуре, ориентированный на эти сценарии. Прикладной уровень (службы WCF) может затем вызывать эти репозитории, которые просто заполняют сводные DTO напрямую, а не отображают сущности домена в DTO.

**** Обновление 2 ****

Хотя я спрашивал об этом более года назад, я подумал, что просто добавлю, что с тех пор я обнаружил CQRS, который нацелен на решение именно этой проблемы. Уди Дахан (http://www.udidahan.com/) и Грег Янг (http://codebetter.com/gregyoung/)) много писали об этом. Если вы создаете распределенное приложение с DDD, CQRS для вас!

Ответы [ 2 ]

25 голосов
/ 20 января 2010

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

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

Но имейте в виду, что вы просто создаете информационные значения вне модели для отображения цели.Поэтому, если пользователь выбирает один бит информации для выполнения какой-либо операции с ним (что определено в модели предметной области), вам необходимо извлечь идентификатор из информационных значений и извлечь объект / совокупность объекта / значения из хранилища.

Я настоятельно рекомендую это видео: Эрик Эванс: Что я узнал о DDD со времени выхода книги .Если вы читаете его книгу, вы действительно должны увидеть все видео.Обратите особое внимание на время около 30:00, когда сам Эрик Эванс говорит об агрегатах и ​​ссылается на проблему, с которой вы столкнулись в настоящее время.

1 голос
/ 20 января 2010

Я бы:

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

Если T в вашем базовом репозитории - это Клиент, то я думаю, что вы неправильно применяете концепцию совокупных корней, хотя я не строгий Evansangelist . Я бы разработал хранилище для Клиента, которое возвращало бы любые данные, которые логически или удобно группируются с Клиентом, включая DataTables или объекты только для чтения, которые являются представлениями данных Клиента.

...