спящий режим и странности jpa; неожиданная отложенная выборка

#java #database #hibernate #orm #jpa

#java #База данных #спящий режим #orm #jpa

Вопрос:

Я использую довольно старую версию Hibernate (3.2.4), так что, возможно, это связано с этим. К сожалению, требования проекта не позволяют мне выполнить обновление.

У меня есть класс Foo с ассоциацией «многие к одному» для Bar. Связь помечена:

 lazy="false" fetch="join"
  

Теперь, когда я делаю что-то вроде:

 em.find(Foo.class, id);
  

Я получаю ожидаемый результат: единственный оператор, соединяющий таблицу FOO с таблицей BAR. Однако, когда я пытаюсь что-то вроде:

 em.createQuery("select f from Foo where f.id = :id")
.setParameter("id", id)
.getSingleResult();
  

Я получаю единственное соединение, за которым следует дополнительный запрос select к BAR. Второй запрос кажется совершенно излишним; все данные, необходимые для быстрого заполнения экземпляра Foo, должны были быть доступны при первоначальном соединении. Это выглядит примерно так:

 select f.id, f.xyz, ..., b.id, b.xyz, ... 
from foo f 
join bar b on b.id = f.bar_id 
where f.id = ?

select b.id, b.xyz, ... 
from bar b 
where b.id = ?
  

Есть мысли?

Ответ №1:

Режим гибернации не соблюдается fetch = "join" при выполнении запросов HQL. Из документации:

Стратегия выборки, определенная в документе сопоставления, влияет:

  • извлечение с помощью get () или load()
  • извлечение, которое происходит неявно при переходе по ассоциации
  • Запросы критериев
  • Запросы HQL, если используется выборка по дополнительному выбору

В случае запросов HQL вам придется использовать left join fetch :

 em.createQuery("select f from Foo f left join fetch f.bar where f.id = :id")
    .setParameter("id", id)
    .getSingleResult(); 
  

Комментарии:

1. Да, я понял это постфактум. Есть ли способ в HQL / JPA-QL указать «join fetch all associations», чтобы мне не приходилось их перечислять? Кажется, что Hibernate поддерживает это с помощью запросов критериев (setFetchMode), но я ограничен интерфейсом JPA.

2. @user190758: Я думаю, что нет, поскольку Hibernate обладает гораздо большей свободой при построении запросов критериев, чем при переводе запросов HQL.

3. Чувак, это отстой. Знаете, возможно ли «преобразовать» запрос HQL в экземпляр criteria, для которого я мог бы программно вызвать setFetchMode()? Или, возможно, подсказка, которую я мог бы перевести в спящий режим с помощью метода JPA setHint ()?