У меня есть четыре таблицы:
RootNode // Will return multiple root nodes
SubNode // Will return one sub node per root node
SubNodeChildren1 // Will return multiple for each sub node
SubNodeChildren2 // Will return multiple for each sub node
и аналогичная структура объекта:
RootNode -> SubNode -> SubNodeChildren1
-> SubNodeChildren2
Мне нужен один запрос, который вернет все корневые узлы
в таблице с инициализированными дочерними подузлами
и подузлами
. Подузел
извлекается быстро, но дочерние узлы Подузел
выбираются лениво.
Я знаю, как написать запрос, который будет LEFT OUTER JOIN FETCH
непосредственными дочерними элементами таблицы и соответственно инициализировать их. Однако я понятия не имею, как получить дочерние элементы таблицы, которая с нетерпением извлекается из таблицы верхнего уровня.
Я пробовал что-то вроде:
SELECT rn FROM RootNode AS rn LEFT OUTER JOIN FETCH rn.SubNode.SubNodeChildren1
, но это всегда дает мне ошибку, что владелец не является частью SELECT.
Любая помощь приветствуется.
Здесь идет ссылка на Hibernate
Единственная причина, по которой нам может понадобиться псевдоним, - это , если мы рекурсивно присоединяемся к получению следующей коллекции
Это означает, что ваш запрос должен быть переписан как
select distinct
rn
from
RootNode rn
left join fetch
rn.subNode sn
left join fetch
sn.subNodeChildren
Вы можете либо
отключить подузел по умолчанию fetch = FetchType.EAGER и просто получить то, что вы действительно хотите, с помощью запроса HQL - он (запрос HQL) эффективно отменяет внешнее соединение и ленивые объявления файла сопоставления для ассоциаций и коллекций (Справочная документация по Hibernate). Этот подход поддерживается POJO в книге действий.
или включите сбор SubNodeChildren как fetch = FetchType.EAGER
Следующее было извлечено из FAQ по Hibernate (ссылка была отключена (насколько мне известно), но я сохранил перед исчезновением)
В приложении MVC, как мы можем гарантировать, что все прокси и ленивые коллекции будут инициализированы, когда представление пытается получить к ним доступ?
Один из возможных подходов - оставить сеанс открытым (и транзакцию незафиксированной) при пересылке в представление. Сеанс / транзакция будет закрыта / зафиксирована после того, как представление будет отрисовано, например, в фильтре сервлета (другой пример - использование обратного вызова ModelLifetime.discard () в Maverick). Одна из трудностей с этим подходом заключается в том, чтобы убедиться, что сеанс / транзакция закрывается / откатывается, если при рендеринге представления возникает исключение.
...
Другой подход - просто принудительно инициализировать все необходимые объекты с помощью Hibernate.initialize (). Часто это проще, чем кажется.
Чтобы запрос работал, мне пришлось выполнить INNER JOIN FETCH
вместо LEFT OUTER JOIN FETCH
на нетерпеливой сущности:
SELECT rn FROM RootNode AS rn INNER JOIN FETCH rn.SubNode AS sn LEFT OUTER JOIN FETCH sn.SubNodeChildren1 LEFT OUTER JOIN FETCH sn.SubNodeChildren2 ...
Честно говоря, я до сих пор не совсем понимаю, почему он работает с INNER JOIN FETCH
по сравнению с LEFT OUTER JOIN FETCH
, но он определенно работает именно так, как мне нужно это к.