репозитории и запросы с помощью необработанного sql?

Я изо всех сил пытаюсь понять, как лучше всего запросить репозиторий.

Три фактора, которые прямо сейчас бросают меня в тупик:

  1. Тип возвращаемых данных
  2. Столбцы для выполнения запроса
  3. Количество возвращаемых записей

Пункт 1

Что касается вопроса один:

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

Пункт 2 Должен ли я при выполнении запроса включать каждый столбец в таблицу, даже если мне нужен только один или два столбца? Если я создам для этого специальные запросы, это приведет к увеличению количества методов в репозитории.

Точка 3 Как предоставить условия для запроса? Я читал о спецификациях, но, насколько я понимаю, вы перебираете возвращенные записи и отфильтровываете те, которые переходят в новую коллекцию. Это не похоже на хорошую идею с точки зрения производительности. Прямо сейчас я просто создаю новый метод в репо, например getNameById(), который инкапсулирует условие.

Обратите внимание, что я не использую ORM, у меня просто есть необработанный sql в моих репозиториях.

Обновить

Пункт 1. Основываясь на ответах и ​​небольшом количестве дополнительных исследований, будет ли это хорошей реализацией?

Прямо сейчас у меня есть большой репозиторий, который возвращает смесь объектов скалярного и сущностного типов (все они одинаковые). Я думаю, что мог бы значительно уменьшить это, если бы просто использовал метод GetUser(userId) и забыл о написании методов, которые просто возвращают значения одного столбца.

Например, если мне нужно вернуть имя пользователя, я мог бы вызвать метод GetUser(userId), который гидратирует объект пользователя, а затем на уровне сервиса просто отфильтровать его до имени пользователя.

Другой способ - использовать какой-то класс QueryBuilder, который я мог бы передать в репозиторий, который можно было бы проанализировать для создания правильного sql.

Пункт 2

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

Точка 3

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

В целом, все еще изучаю это... Я хотел бы услышать больше информации об этом или ссылок на книги или ссылки, которые связывают все это воедино.


person chobo    schedule 27.02.2012    source источник
comment
Вы создаете команду Sql динамически в своем классе?   -  person Arian    schedule 28.02.2012
comment
Чистый SQL и никакого ORM, ха? Как жить на краю, не так ли? Серьезно, почему вы хотите иметь дело с сырым sql?   -  person Yves Reynhout    schedule 28.02.2012
comment
@kerezo - у меня есть параметры sql и я использую значение addwith   -  person chobo    schedule 28.02.2012


Ответы (4)


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

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

Должен ли я при выполнении запроса включать каждый столбец в таблицу, даже если мне нужен только один или два столбца? Если я создам для этого специальные запросы, это приведет к увеличению количества методов в репозитории.

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

Как я должен предоставить условия для запроса? Я читал о спецификациях, но, насколько я понимаю, вы перебираете возвращенные записи и отфильтровываете те, которые переходят в новую коллекцию. Это не похоже на хорошую идею с точки зрения производительности. Прямо сейчас я просто создаю новый метод в репо, например getNameById(), который инкапсулирует условие.

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

Что касается «Необработанного SQL против ORM в DDD», вы можете найти этот ответ интересным.

person Dmitry    schedule 27.02.2012
comment
Не могли бы вы указать на некоторые ответы или учебные пособия, которые решают эту проблему доступа к данным? - person chobo; 28.02.2012
comment
В самой книге DDD есть пример спецификации, которая преобразуется в необработанный SQL из-за соображений производительности. - person Dmitry; 28.02.2012
comment
Это синий от Эрика Эванса? Случайно не знаете номер страницы этого примера? :) - person chobo; 28.02.2012

Я согласен со всем, что говорит Дмитрий, но, возможно, вам следует прочитать CQRS.

Когда я начинал работу с DDD, я задавал подобные вопросы (о «взрыве метода», а не о проблемах с SQL), и это привело меня к CQRS. Лично я не очень понимаю, насколько DDD практична без него, и он отвечает на множество подобных вопросов, когда дело доходит до запроса данных. Используя его принципы, я бы предложил:

  1. Используйте репозитории домена только при совершении транзакции. То есть вы не используете репозитории для отображения данных в пользовательском интерфейсе. Вы извлекаете агрегаты из своего репозитория только тогда, когда хотите выполнить над ними операцию.
  2. Ваши репозитории возвращают только агрегаты, а не отдельные объекты по отдельности. Теперь это имеет смысл, так как мы используем репозитории только в транзакционном смысле, а сущности могут быть изменены только с помощью атомарных операций и сохранены агрегатом в целом.
  3. Вы создаете отдельные репозитории (или «службы запросов»), которые предоставляют индивидуальные запросы и типы данных для любых данных, которые вам нужны. Они могут возвращать глупые DTO без какой-либо логики.

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

Что касается шаблона спецификации: вместо того, чтобы преобразовывать его в SQL-запрос в коде, вы можете предоставить общедоступные свойства в спецификации, которые представляют критерии. Затем эти значения могут быть добавлены в предложение where вашего SQL или отправлены в качестве параметров в SPROC.

person David Masters    schedule 28.02.2012

Прежде всего, вы толком не объяснили, для чего вы используете все эти запросы. Скорее всего, это для нужд пользовательского интерфейса. Если это так, нет необходимости прыгать через все эти обручи (сервис-> репозиторий-> домен-> dto-> клиент), просто запросите базу данных как можно напрямую. И что вы знаете, исчезли вопросы о том, можете ли вы запрашивать скаляры или только нужные вам столбцы. Просто используйте простой sql и верните то, что вам нужно. Не создавайте абстракции, которые вызывают трения.

person Yves Reynhout    schedule 27.02.2012
comment
Все, что я ищу, - это передовой подход к запросам репозиториев, поэтому у меня нет миллиона методов, и это каким-то образом также влияет на приличную производительность. - person chobo; 28.02.2012
comment
Начните с того, что не добавляйте их в репозиторий, если они не служат цели домена. Переместите их на другой фасад, который представляет запросы, необходимые пользовательскому интерфейсу. Идите так быстро от клиента к фасаду, к БД, к фасаду, к клиенту. Используйте простые DTO для представления состояния, которое необходимо передать клиенту. - person Yves Reynhout; 28.02.2012

Чобо,

Нам нужно помнить две вещи о шаблоне Repository [Fowler PoEAA][Evans DDD]:

  1. Используйте шаблон репозитория как простую коллекцию. Репозиторий абстрагирует эти детали инфраструктуры, потому что они не из домена.
  2. Если шаблон репозитория является коллекцией, это кластер объектов одного типа.

Два других типа могут помочь вашему репозиторию: шаблоны Query Object [Fowler PoEAA] и Data Mapper [Fowler PoEAA]. Критерии агрегирования шаблона Query Object с использованием объектно-ориентированных методов и знание того, как преобразовать их в оператор SQL. Паттерн Data Mapper умеет сопоставлять состояния объектов из приложения и столбцы таблицы из баз данных.

Вы можете использовать шаблон отложенной загрузки [Fowler PoEAA], чтобы смягчить проблему больших объектов в памяти.

Успехов вам!

person lcardosobr    schedule 29.02.2012
comment
Я думаю, что Query Object очень поможет с проблемой запросов по разным критериям. Я предполагаю, что это встроено в ORM. Спасибо за список шаблонов, решающих эти проблемы! - person chobo; 01.03.2012