репозитории и запросы с сырым sql? - PullRequest
7 голосов
/ 28 февраля 2012

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

Три фактора, которые бросают меня через цикл сейчас:

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

Точка 1

В отношении первого вопроса:

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

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

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

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

Обновление

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

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

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

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

Point 2

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

Точка 3

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

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

Ответы [ 4 ]

3 голосов
/ 28 февраля 2012

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

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

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

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

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

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

Относительно 'Raw SQL против ORM в DDD' вы можете найти этот ответ интересным.

2 голосов
/ 28 февраля 2012

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

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

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

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

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

1 голос
/ 29 февраля 2012

Chobo,

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

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

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

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

Удачи вам!

1 голос
/ 28 февраля 2012

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

...