HQL оставил соединение несвязанных сущностей - PullRequest
44 голосов
/ 27 марта 2012

У меня есть 2 сущности, A и B.Они связаны, но я не хочу добавлять сопоставление отношений к bean-компонентам.

Как мы можем использовать левое внешнее соединение между A и B с использованием HQL или критериев ?

Для этого есть несколько обходных путей:

  1. Использовать собственный SQL, как сказано здесь .
  2. Добавить отношение и использовать выбратьa из A левое соединение ab .
  3. Мы можем сделать внутреннее соединение в HQL как выбрать * из A a, B b, где a.some = b.Some

Я всегда возвращался к этим 2 вариантам, есть ли альтернатива для этого?Или это невозможно?

Ответы [ 4 ]

56 голосов
/ 04 апреля 2012

В настоящее время тэта-стиль при присоединении несвязанных классов в предложении where с использованием HQL поддерживает только внутреннее соединение.

Запрос для поддержки внешнего объединения для такой ситуации в настоящее время является третьим наиболее востребованным улучшением , но я не думаю, что эта функция будет реализована в ближайшей функции, так как сначала требуется повторная реализация текущего синтаксического анализатора запросов на основе ANTLER , что представляется гигантской задачей IMO.

Если вы настаиваете на использовании HQL для выполнения левого соединения без добавления отношения между A и B, вы можете использовать опцию 3, чтобы сначала выполнить внутреннее соединение, а затем использовать следующий HQL

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

, чтобы найти все A, которые не могут присоединиться к B, и программно объединить результаты.

Обновление

Начиная с версии 5.1.0 HHH-16 (Явные объединения на несвязанных классах) исправлено, и мы должны иметь возможность присоединиться к несвязанным сущностям.

3 голосов
/ 04 апреля 2012

Как сказал Кен Чан, вы не можете сделать это напрямую в одном запросе HQL.

Относительно ваших трех возможностей:

  1. Собственный SQL: не рекомендуется. Синтаксис внешних объединений в разных базах данных весьма различен.
  2. Добавить отношения: Я бы так и сделал. Он не требует больших затрат кода или памяти и быстро программируется.
  3. Внутреннее соединение: это не работает (пропущенные строки), если отношение действительно является внешним соединением в базе данных.

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

(Решение аналогично предложенному Кеном Чаном, но оно избегает «не в» и внутреннего выбора, которые оба могут быть неэффективными в базе данных.)

1 голос
/ 14 февраля 2017

Если вы знаете, что для каждого A есть максимум 1 B, вы также можете использовать подзапрос.

Например:

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

Если вы знаете, что существует хотя бы 1B, вы также можете использовать следующий запрос, но это не рекомендуется, поскольку это взломать:

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))
0 голосов
/ 29 марта 2012

Смелое утверждение: Вы не можете.

Почему?JPQL (и HQL) ожидает путь между сущностями, чтобы присоединиться к ним.

Что я обычно делаю в такой ситуации (предпочтительный порядок):

  1. Связатьобъекты.
  2. Получите данные, необходимые для программного сбора результатов.
  3. Либо 1, либо 3 из трех опций, которые вы уже упомянули.
...