c0nstruct0r
@c0nstruct0r
PHP программист

Как делать сложные запросы используя репозитории и объединение разных таблиц?

Приветствую!
Меня учили работать с domain driven design. В рамках этого подхода мне предложили разделить доступ к данным по репозиториям. То есть на одну таблицу БД в нашей компании предлагается использовать один репозиторий. С простыми запросами все понятно.

Как в рамках этого подхода использовать данные из нескольких таблиц? На уровне БД это решается просто - join и подзапросы. На уровне репозитория мне не понятно как это делать. Я вижу два варианта. Использовать запросы с join и подзапросами для получения всех нужных данных как частный случай какой-то задачи, сделать отдельный метод в репозитории который будет уметь такое. Второй вариант это получать данные разными запросами и объединять их на уровне сервиса каким-то маппингами.
Мапиинги в обоих случаях придется использовать так как например если мы хотим отдать по API список заказов с товарами то в объекте заказа будет поле-массив с коллекцией объектов-товаров соответствующего типа.
Все это медленно работает.
Вероятно я не понимаю как правильно спроектировать такое приложения. Прошу Вас помочь с решением этой несложной задачки. Заранее благодарен все откликнувшимся.
  • Вопрос задан
  • 462 просмотра
Пригласить эксперта
Ответы на вопрос 3
FanatPHP
@FanatPHP
Чебуратор тега РНР
решением этой несложной задачки.

Уважаю такой оптимизм.

Проблема эта не нова. Называется она object-relational impedance mismatch и очень многие считают её в принципе нерешаемой, сравнивая её с проигранной США войной во Вьетнаме.
Так что можно надеяться на что угодно, только не на простое решение. Но сначала надо проблему осознать. Что отображение объектов на реляционную базу, которое называется object-relational mapping, сокращённо ORM, никогда не бывает простым.

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

К примеру, "нерешаемость" проблемы с impedance mismatch относится к попыткам сделать универсальный ORM, который на вход получает имя любого класса, а на выходе коллекцию объектов. Про такой вариант можно действительно забыть (привет, элоквент-элоквент - и в продакшен!). Но вот полуавтоматическое решение вполне можно накостылить. Главное всегда помнить о проблеме, и как только автоматический маппинг перестаёт работать - тут же от него оказываться в пользу ручного колупания с запросами. Главное этого не бояться и не загонять себя в клетку словами "репозиторий", "один объект-одна таблица" и пр. У тебя есть задача - инстанцировать объект или коллекци объектов из БД. Окей, ты пишешь методы, которые это делают оптимальным способом, не важно - одна там таблица используется, 10 или еще плюс 2 кэша и носкл датабаза в придачу.
Надо тебе сохранить объект или коллекци объектов в БД? Окей, пишешь метод, коорый делает это оптимальным способом. Да, это куча черной работы. Но зато у тебя будет чистая доменная логика (которая вообще никакого отношения к базе данных или "репозиториям" не имеет).

Отдельно прекламирую Cycle ORM. Сам я ненастоящий сварщик, но взрослые дядьки говорят что она лучше всего подходит для нормально реализованного маппинга объектов на БД. Лучше чем Доктрина или прости-господи Элоквент. С нетерпением жду доклада автора на ПХПРаша.
Ответ написан
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
Совет в лоб. Следуя ООП вы описываете объекты системы объектами из внешнего мира. И все у вас шикарно пока вы не начинаете нормализовывать схему БД. Видимо вас это беспокоит?

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

Есть бизнес модели, например Группа и Пользователь
Кроме очевидных 2 таблиц добавляется 3 ПользовательВГруппе
Вам очевидно нужно только 2 репозитория, 3 репозиторий будет лишним и внесет только путаницу
Ответ написан
@majstar_Zubr
C++, C#, gamedev
Можно использовать представления со стороны БД, либо фабрики хранилищ со стороны кода.
Модно сначала просто статически запечь в отдельный класс, если это действительно узкое место. Если паттерн себя проявит, то можно оформить в виде фабрики.

Вон в C# в Entity Framework почти как вы сказали, только там запрос конструируется из коллекций классов, которые умеют в маппинг конкретной предметной области. Но там на выходе уже полноценная ORM с оптимизациями типа отложенного запроса к БД: технология Linq-To-Entity реализует реляционную логику, так что громоздкий SQL запрос модно отложить до самого последнего момента.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы