Подтвердить что ты не робот

Как объединить LEFT JOIN и Where where с JPQL?

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

  • Расписание (содержащий список резервирований)
  • Бронирование (содержит поле Date: Date resDate)

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

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

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.

4b9b3361

Ответ 1

А, это действительно классика в 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 также достаточно эффективен. Если кто-нибудь сможет объяснить, почему это работает, я буду очень впечатлен. Я узнал эту закономерность несколько лет назад, но не могу за всю жизнь помнить, где.

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

Ответ 2

В 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

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

FROM запросов t0, пользователей t1 WHERE ((t1.ID = t0.assignee_id)) ORDER BY CASE КОГДА (t0.assignee_id IS NULL) THEN? ELSE t1.ID END DESC) WHERE 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

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

FROM request t1 LEFT OUTER JOIN users t0 ВКЛ (t0.ID = t1.assignee_id) ORDER BY CASE КОГДА (t0.ID NULL) THEN? ELSE t0.ID END DESC) WHERE ROWNUM < =?) WHERE rnum > ?

Ответ 3

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

Напоминание начальной цели:

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

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

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

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