Правильная выборка Doctrine
Имеется Entity User: username, roles (json) и т.д.
Имеется Entity Appointment: patient_id, doctor_id и т.д.
Мне нужно составить такой запрос, чтобы вернул всех уникальных пользователей, где doctor_id = нужному. DISTINCT в данном случае не подходит из-за поля roles. Как правильно составить запрос?
Приведу в пример свой случай: имеется 3 записи в Appointment с одинаковыми doctor_id и patient_id. Когда делается выборка пользователей через inner join Appointment, то пациент возвращается трижды после запроса, что нарушает пагинацию и вывод общего количества.
$pageQb = $this->createQueryBuilder('u');
$pageQb->select('count(u.id)');
$qb = $this->createQueryBuilder('u');
$qb->join('u.appointments', 'a')
->andWhere("a.doctor = :doctor")
->setParameter("doctor", $searchParams['doctor']);
$pageQb->join('u.appointments', 'a')
->andWhere("a.doctor = :doctor")
->setParameter("doctor", $searchParams['doctor']);
$qb->setFirstResult(($page - 1) * $pageSize);
$qb->setMaxResults($pageSize);
try {
$totalEntities = (int) $pageQb->getQuery()->getSingleScalarResult();
$totalPages = ceil($totalEntities / $pageSize);
} catch (NoResultException $e) {
$totalEntities = 0;
$totalPages = 0;
} catch (NonUniqueResultException $e) {
$totalEntities = 0;
$totalPages = 0;
}
return [$totalEntities, $totalPages, $qb->getQuery()->getResult()];
pageQb->getQuery()->getSingleScalarResult() вернет 3, $qb->getQuery()->getResult() вернет одну уникальную запись, но если повторить этот запрос в БД, то там тоже будет 3 записи. На пагинацию это тоже влияет
doctor и patient - это Entity User, связь ManyToOne.
UPD: Итого, пришел к следующему варианту на данный момент:
$qb = $this->createQueryBuilder('u');
$qb->join('u.appointments', 'a')
->andWhere("a.doctor = :doctor")
->setParameter("doctor", $searchParams['doctor']);
$qb->setFirstResult(($page - 1) * $pageSize);
$qb->setMaxResults($pageSize);
$paginator = new Paginator($qb, false);
$totalEntities = $paginator->count();
$totalPages = (int) ceil($totalEntities / $pageSize);
$users = [];
foreach ($paginator as $user) {
$users[] = $user;
}
return [$totalEntities, $totalPages, $users];
Ответы (1 шт):
Когда доктрина получает результат из базы и создаёт объекты сущностей, она не отображает каждую найденную строку на отдельную сущность, она немного умнее. Она знает, что при джойне часть колонок будет дублироваться, и она правильно обработает все строки не создавая лишних сущностей. В итоге запрос у вас корректный.
Но пагинация в случае с джойном тоже не так проста. У вас будут дублироваться колонки в строках результата (сделайте запрос без count в любом mysql-клинте и посмотрите на результат запроса с join). Чтобы вы не заморачивались с пагинацией каждый раз (хотя я советую вам заморочиться хотя бы один раз, просто чтобы понимать как это работает) доктрина содержит специальные инструменты для пагинации. Вы создаёте объект пагинатора и можете вызвать count($paginator), чтобы получить общее количество страниц. Чтобы всё сработало, не забудьте использовать setFirstResult и setMaxResults.