web-dev-qa-db-ja.com

HQLは無関係なエンティティの左結合

ABの2つのエンティティがあります。それらは関連していますが、関係マッピングをBeanに追加したくありません。

HQLまたは基準を使用してABの間に左外部結合を使用するにはどうすればよいですか

これにはいくつかの回避策がありますが、

  1. here のようにネイティブSQLを使用します。
  2. 関係を追加し、を使用してAから選択し、左結合a.bを選択します。
  3. HQLでinner joinを行うことができますselect * from a a、B b where a.some = b.some

私は常にこれら2つのオプションに戻っていましたが、これに代わるものはありますか?またはこれは不可能ですか?

44
ManuPK

現在、HQLを使用してwhere句で無関係なクラスを結合するthetaスタイルは、内部結合のみをサポートしています。

request このような状況で外部結合をサポートすることは 現在3番目に投票数が多い拡張機能 ですが、この機能が近い機能に実装されるとは思わない 現在のANTLERベースのクエリパーサーの再実装 が必要です。これは巨大なタスクIMOのようです。

AとBの関係を追加せずにHQLを使用して左結合を実行することを主張する場合、オプション3を使用して最初に内部結合を実行し、次のHQLを使用できます

from A a where a.some not in ( select b.some from B)

bに参加できないすべてのAを見つけ、プログラムで結果を結合する。

更新

リリース5.1.0から HHH-16(無関係なクラスでの明示的な結合) が修正され、無関係なエンティティを結合できるはずです。

57
Ken Chan

Ken Chanが言ったように、1つのHQLクエリで直接行うことはできません。

あなたの3つの可能性に関して:

  1. ネイティブSQL:推奨できません。外部結合の構文は、データベースによって大きく異なります。
  2. 関係を追加する:それは私がやることです。コードやメモリをあまり消費せず、すぐにプログラムできます。
  3. 内部結合:リレーションが実際にデータベース内の外部結合である場合、機能しません(行がありません)。

何らかの特別な理由でリレーションシップを本当に追加したくない場合は、クエリを2つの個別のクエリに分割し、次のようにJavaで結果を手動で結合できます。

Query qa = session.createQuery("from A a");
List la = qa.list();

Query qb = session.createQuery("select distinct b.* from B b, A a where a.some=b.some");
List lb = qb.list();

Map bMap = new HashMap();
for (B b : lb) {
  bMap.put(b.getId(), b);
}

/* example with for loop */
for (A a : la) {
  B b = bMap.get(a.getForeignKeyForB());
  /* now you have A a and the outer joined B b and you can do with them what you want */
  ...
}

このソリューションの実行時間とメモリのコストは、データベースの外部結合とほぼ同じです(ソリューション2)。もう少しJavaコード。

(この解決策はKen Chanが提案したものと似ていますが、「not in」と内部選択を回避しています。どちらもデータベースでは非効率的です。)

3
Johanna

すべてのAに最大1つのBがあることがわかっている場合は、サブクエリも使用できます。

例えば:

select a, (select b from B b where b.some = a.some)
from A a

少なくとも1つのBが存在することがわかっている場合は、次のクエリも使用できますが、ハックであるためお勧めできません。

select a, (select b4 from B b4 where b4=b and b4.some=a.some) from A a, B b 
where a.some=b.some or (a.some not in (select b2.some from B b2) 
and b.id = (select min(b3.id) from B b3))
1