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

HQL левое соединение несвязанных объектов

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

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

Для этого есть некоторые обходные пути,

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Update

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

Ответ 2

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

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

  • Исходный SQL: Не рекомендуется. Синтаксис внешних соединений довольно различен между различными базами данных.
  • Добавить отношения: Что бы я сделал. Это не дорогого кода или памяти, и это быстро запрограммировано.
  • Внутреннее соединение: это не работает (недостающие строки), если отношение действительно является внешним соединением в базе данных.

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

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

Ответ 3

Если вы знаете, что для каждого 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))

Ответ 4

Жирный оператор: вы не можете.

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

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

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