web-dev-qa-db-ja.com

LEFT JOINおよびWhere句をJPQLと組み合わせる方法は?

2つのJPAエンティティがあります:

  • スケジュール(予約リストを含む)
  • 予約(日付フィールドを含む:Date resDate)

私の目標は、この特定の日付に予約が存在するかどうかに関係なく、すべてのスケジュールを取得しながら、日付パラメーター(planningDate)に一致する予約のみを取得することです。

だから私は書いた:

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

LEFT JOINにもかかわらず、この日付の予約なしでスケジュールが取得されないのはなぜですか?

おそらく、ネイティブクエリと同様に、WHERE句と組み合わせると、LEFTJOINはINNERJOINのように見えます。

では、要件を満たすためにクエリをどのように変更できますか? JPQLに特定の機能が見つかりません。

12
Mik378

ああ、これは確かに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.resDateisnull」の部分です)

長い答え:これは休止状態/ JPAの人々によって機能しないと明示的に言われていますが、機能します。生成されたSQLも非常に効率的です。なぜこれが機能するのか誰かが説明できれば、私は最も感銘を受けます。私は何年も前にこのパターンを学びましたが、私の人生のどこにいるのか思い出せません。

注:これが機能しない場合が1つあります。これは、このスケジュールの予約がない場合です。この場合、私が提供できる唯一の答えは、クエリを「NoResultException」のtry/catchでラップし、where句なしで再度クエリを実行できることです(明らかに、予約がない場合は、resDateがオンの予約はありません) PlanningDate)

14
Chaos

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 WHEN(t0.assignee_id IS NULL)THEN?ELSEt1。 ID END DESC)WHERE ROWNUM <=?)WHERE 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はt1 LEFT OUTER JOINユーザーt0を要求します ON(t0.ID = t1.assignee_id)ORDER BY CASE WHEN(t0.ID IS NULL)THEN?ELSEt0。 ID END DESC)WHERE ROWNUM <=?)WHERE rnum>?

2
zealot

最後に、JPAのLEFTJOINの概念が適用できない場合があると思います。

最初の目標を思い出させる:

特定のplanningDateに一致する場合に、予約コレクションにのみデータを入力している間に発生したすべてのスケジュールを取得します(これらのそれぞれのスケジュールではそうです)。

実際、予約が私の基準に一致しないスケジュールを取得できたとしても、フェッチタイプが「熱心」であると宣言されている場合、それらのスケジュールは予約のコレクションをそれぞれ再読み込みするため、正確な「planningDate」への制限句。これは、他の制限なしにすべてのスケジュールのすべての予約を選択するのとまったく同じ動作です。

したがって、JPAでの私の問題に対する最も単純な適応ソリューションは、2つの要求を行うことです。最初にスケジュールを選択し、次にplanningDateに一致する予約を選択します。したがって、結果を1つのリストに再グループ化して、返すことができます。欠点は、予約コレクションが時間にロードされることです。

より良い解決策を見つけたら、私は感謝します。

1
Mik378