Как объединить предложения LEFT JOIN и Where с JPQL? - PullRequest
12 голосов
/ 14 февраля 2012

У меня есть два объекта JPA:

  • Расписание (содержащее список бронирований)
  • Резервирование (с полем Дата: Дата пересчета)

Моя цель состоит в том, чтобы получать только резервирования, соответствующие параметру даты (planningDate), при извлечении всех расписаний, независимо от того, существует резервирование или нет на данную дату.

Итак, я написал:

SELECT s FROM Schedule as s LEFT JOIN s.reservations as r WHERE r.resDate = :planningDate order by s.startHour

Почему расписания, без оговорок на эту дату, не возвращаются, несмотря на мое левое соединение?

Вероятно, подобно собственным запросам, LEFT JOIN выглядит как INNER JOIN при объединении с предложением WHERE.

Итак, как можно изменить запрос для выполнения моего требования? Я не нашел какой-либо особенной функции в JPQL.

Ответы [ 3 ]

14 голосов
/ 16 марта 2012

Ах, это действительно классика в JPA. Следующий ответ, который я предоставляю - я не могу объяснить точно , почему это работает, но я могу решить это для вас

Краткий ответ , попробуйте:

SELECT s FROM Schedule as s LEFT JOIN s.reservations as r WHERE 
(r.resDate is null or r.resDate = :planningDate) order by s.startHour

(ключ здесь - часть "r.resDate is null")

Длинный ответ : Говорят, что люди, работающие в спящем режиме / JPA, явно не работают, но это работает. Сгенерированный SQL также довольно эффективен. Если кто-нибудь может объяснить, почему это работает, я буду очень впечатлен. Я выучил эту модель много лет назад, но не могу на всю жизнь вспомнить, где.

Одно примечание: есть один случай, когда это не сработает, и это в случае, когда нет резервирований для этого расписания. В этом случае единственный ответ, который я могу дать, состоит в том, что вы можете заключить свой запрос в попытку / перехват для «NoResultException» и выполнить запрос снова без предложения where (очевидно, если нет никаких резервирований, то нет резервирований с resDate на planningDate)

2 голосов
/ 21 марта 2014

В EclipseLink 2.5 (Glassfish 4.0, база данных Oracle 11g XE):

Не работает (псевдоним не назначен r.assignee):

from Request r left join r.assignee 
order by case when r.assignee.id is null then 0 else r.assignee.id end desc

Сгенерированная часть запроса (используетсяdecart умножение):

ОТ запросов t0, пользователи t1 ГДЕ ((t1.ID = t0.assignee_id)) ЗАКАЗАТЬ ПО СЛУЧАЮ КОГДА (t0.assignee_id IS NULL), ТО?ELSE t1.ID END DESC) ГДЕ ROWNUM <=?) ГДЕ rnum>?

Работает (добавлено a псевдоним для r.assignee):

from Request r left join r.assignee as a
order by case when a.id is null then 0 else a.id end desc

Сгенерированная часть запроса (используется левое соединение):

ОТ запросов t1 ЛЕВЫЕ ВНЕШНИЕ СОЕДИНИТЕЛИ пользователей t0 ВКЛ (t0.ID = t1.assignee_id) ORDER BY CASE WHEN (t0.ID NULL) ТОГДА?ELSE t0.ID END DESC) ГДЕ ROWNUM <=?) ГДЕ rnum>?

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

Наконец, я думаю, что есть случай, когда концепция LEFT JOIN в JPA не может быть применена.

Напоминание исходной цели:

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

Действительно, даже если мне удастся получить расписания, резервирование которых не соответствует моим критериям, эти расписания, в любом случае, перезагрузят свои коллекции резервированийсоответственно, если они объявлены с типом выборки как «нетерпеливый», и, таким образом, это не влияет на условие ограничения для уточненной «PlanningDate».Это поведение в точности аналогично выбору всех резервирований всех расписаний без ЛЮБЫХ других ограничений.

Таким образом, наиболее простым адаптированным решением моей проблемы в JPA было бы сделать 2 запроса: сначала выбрать расписания, а затем выбрать соответствующие резервирования для PlanningDate во втором и независимо.Таким образом, результаты могут быть сгруппированы в один список и возвращены.Недостатки в том, что коллекции резервирований загружаются в разы.

Если вы найдете лучшее решение, я был бы признателен.

...