Описание на проблема

Както казахме по-горе, анотацията LazyCollectionOption.EXTRA има проблем - тя изпълнява отделна заявка към базата данни за всеки обект. Трябва по няHowъв начин да обясним на Hibernate, че искаме незабавно да зареди всички дъщерни обекти за нашите родителски обекти.

Разработчиците на Hibernate са измислor решение на този проблем, операторът за присъединяване в HQL.

Пример за HQL заявка:

select distinct task from Task t left join fetch t.employee order by t.deadline

В тази заявка всичко е просто и сложно едновременно. Нека се опитаме да го конструираме част по част.

Опция 1

Искаме да изтеглим всички обектизадача, подредени по краен срок. Ето How ще изглежда това искане:

select task from Task t order by t.deadline

Докато всичко е ясно. Но полетослужителна класа Task ще съдържа колекция от служители, анотирани с ДОПЪЛНИТЕЛНА анотация . И обектите от тази колекция няма да бъдат заредени.

Вариант 2

Принудително хибернация за зареждане на дъщерни обекти за обектзадача.

select task from Task t join fetch t.employee order by t.deadline

С помощ ние изрично обвързваме обектите Задача и Служител в нашата заявка. Hibernate вече знае това, защото използваме анотациите @ManyToMany в тези полета.

Но имаме нужда от оператор за присъединяване , за да го завършим с оператор за извличане , за да получим извличане на присъединяване . Ето How казваме на Hibernate, че обектите в колекциите Task.employee трябва да бъдат заредени от базата данни, когато нашата заявка се изпълни.

Вариант 3

Предишното решение има няколко грешки. Първо, след използване на join, SQL няма да ни върне обектизадача, които нямат обекти, свързани с тях в tableта Employee. Точно така работи вътрешното присъединяване .

Така че трябва да увеличим нашето съединение с ляв оператор и да го превърнем в ляво съединение . Пример:

select task from Task t left join fetch t.employee order by t.deadline

Вариант 4

Но това не е всичко. Ако във вашия code връзката между обектите е много към може, тогава ще има дубликати в резултатите от заявката. Същият обектзадачамогат да бъдат намерени на различни служители (обекти Employee).

Така че трябва да добавите отделната ключова дума след избраната дума, за да се отървете от дублиращия се обект Task.

select distinct task from Task t left join fetch t.employee order by t.deadline

Така в 4 стъпки стигнахме до заявката, с която започнахме. Е, codeът на Java ще изглежда доста очаквано:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();

JOIN FETCH Ограничения

Никой не е перфектен. JOIN FETCH израз също. Има доста ограничения. И първият използва методите setMaxResults() и setFirstResult() .

За израза JOIN FETCH нашият Hibernate ще генерира много сложна заявка, в която комбинираме три таблици в една: служител, задача и Employee_task. Всъщност това не е заявка за служители or задачи, а за всички известни двойки служител-задача.

И SQL може да приложи своите оператори LIMIT и OFFSET към точно тази заявка от двойки служител-задача. В същото време от HQL заявката ясно следва, че искаме да получим точно задачи (Task) и ако преразпределим нашите параметри FirstResult и MaxResult, тогава те трябва да се отнасят конкретно до обектите Task.

Ако напишете code по този начин:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
       	    query.setFirstResult(0);
        	   query.setMaxResults(1);
return query.list();

Тогава Hibernate няма да може да преобразува правилно FirstResult и MaxResult в параметрите OFFSET и LIMIT на SQL заявката.

Вместо това ще направи три неща:

  • SQL заявката ще избере като цяло всички данни от tableта и ще ги върне в режим на хибернация
  • Hibernate ще избере необходимите записи в паметта си и ще ви ги върне
  • Hibernate ще издаде предупреждение

Предупреждението ще бъде нещо подобно:

WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104: 
firstResult/maxResults specified with collection fetch; applying in memory!