metallix
@metallix
Backend - developer

Как правильно составить QueryBuilder запрос?

Приветствую! С доктриной раньше работать не приходилось, посему обращаюсь за помощью!

Есть сущность House. У неё есть множество one-to-many связаных сущностей -
  • HouseInspection
  • HouseEvaluation
  • HousePriceHistory
  • HouseStatusHistory
  • HouseComment

Все связаные сущности для House подтягиваются как EXTRA_LAZY

Собсно две проблемы:
1) Нужно вытянуть в все связаные сущности (главную House сущность не обязательно) с помощью QueryBuilder ( важно, т.к. позже этот запрос будет модифицироваться для фильтрации и пагинации результатов, а кастомный пагинатор писать - не ок) и отсортировать по полю createdAt (есть у всех сущностей).

2) Для каждого типа сущности, в запросе надо добавить поле(?) тип. т.е. если вытягиваем коллекцию HouseInspection, то в каждой сущности нужно доп. поле обозначающее этот энтити ( e.g. - Inspection, Evaluation, Price, etc.). Это нужно для того, что бы позже модифицировать этот запрос, и вытягивать сущности только определенного типа. На счёт этого пункта, я не уверен - в правильную ли сторону я мыслю. Может это как-то и проще можно реализовать. Хотя, если решить первую проблему, то и сразу решение второй найдется.

Что есть/пробовал :

1)
Джойны

$this->getEntityManager()->createQueryBuilder()
            ->select('h') 
            ->from(House::class, 'h')
            ->leftJoin(HouseHistoryRecord::class, 'sh', Join::LEFT_JOIN, 'sh.house = h.id')->addSelect('sh as statusHistory')
            ->leftJoin(HousePriceHistory::class, 'ph', Join::WITH, 'ph.house = h.id')->addSelect('ph as priceHistory')
            ->leftJoin(HouseEvaluation::class, 'eval', Join::WITH, 'eval.house = h.id')->addSelect('asmt as houseEvaluations')
            ->leftJoin(HouseInspection::class, 'insp', Join::WITH, 'insp.house = h.id')->addSelect('insp as houseInspections')
            ->leftJoin(HouseComments::class, 'cmts', Join::WITH, 'cmts.house = h.id')->addSelect('cmts as houseComments')
            ->where('h.id = :houseId')
            ->setParameter('houseId', $house->getId());
HouseComments

Не ок. Вытягивает только House и подгружает связаные сущности в себя. Собственно пагинация не получится.

2)
Вариант в лоб


$sh = $this->getEntityManager()->createQueryBuilder()
            ->select('sh')
            ->from(HouseHistoryRecord::class, 'sh')
            ->where('sh.house = :houseId')
            ->setParameter('houseId', $house->getId());

        $ph = $this->getEntityManager()->createQueryBuilder()
            ->select('ph')
            ->from(HousePriceHistory::class, 'ph')
            ->where('ph.house = :houseId')
            ->setParameter('houseId', $house->getId());

        $eval = $this->getEntityManager()->createQueryBuilder()
            ->select('eval')
            ->from(HouseEvaluation::class, 'eval')
            ->where('eval.house = :houseId')
            ->setParameter('houseId', $house->getId());

        $insp = $this->getEntityManager()->createQueryBuilder()
            ->select('insp')
            ->from(HouseInspection::class, 'insp')
            ->where('insp.house = :houseId')
           ->setParameter('houseId', $house->getId());

        $cmts = $this->getEntityManager()->createQueryBuilder()
            ->select('cmts')
            ->from(HouseComments::class, 'cmts')
            ->where('cmts.house = :houseID')
            ->setParameter('houseId', $house->getId());


Почти ок. - Всё вытягивает как надо, но в разные коллекции естественно. Может можно как-то все эти запросы в один объеденить? И тогда уже отсортировать по дате?

Чистый SQL (+ ResultSetMapping) не рассматриваю, т.к. его позже сложнее будет кастомизировать для пагинации/фильтрации. Предпочитаю DQL.

Взываю к гуру доктрины. Чувствую что кручусь, где-то рядом, но знаний доктрнины не хватает.

Спасибо заранее!
  • Вопрос задан
  • 48 просмотров
Пригласить эксперта
Ответы на вопрос 1
index0h
@index0h
PHP, Golang. https://github.com/index0h
Вытягивайте отдельными запросами. Иначе в выборку будут попадать пересечения из каждой связи, что может вернуть реально много данных. Да и пагинацию так выйдет проще сделать.
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
от 200 000 ₽
FABRIKA Астрахань
от 60 000 ₽
Ctrlweb Ставрополь
от 80 000 до 100 000 ₽
21 окт. 2020, в 17:12
15000 руб./за проект
21 окт. 2020, в 17:10
15000 руб./за проект