Hibernate. Использование именованных запросов (@NamedQueries) на уровне пакета

Создадим именованный запрос в файле package-info.java, который в дальнейшем будет вызываться по строке с именем. Именованные запросы, вызываемые через методы репозитория, рассмотрены в другой статье.

Если у нас есть некоторый пакет со связанными друг с другом сущностями, например, пакет client с классами-сущностями Client, Address, BillingData и т.п., то может так случится, что у нас будет для этих сущностей некий набор именованных запросов, который было бы удобно хранить в одном месте. Таким местом может быть файл package-info.java, который можно создать в любом java-пакете и поместить в него через аннотации ту или иную метаинформацию о пакете. В частности Hibernate позволяет разместить здесь аннотации, описывающие именованные запросы.

Создадим минимальное Spring Boot приложение с поддержкой JPA/Hibernate.

Добавим в проект следующую сущность:

В пакете, где мы расположили файл Person.java, также создадим файл package-info.java со следующим содержимым:

Как видите директива package com.example.demo.domain; аннотирована аннотацией @NamedQueries. Поскольку это чисто хибернейтовская аннотация, а не стандартная JPA аннотация, то по правилам приличия пишется её полное имя.

В аннотацию @NamedQueries передаётся массив аннотаций @NamedQuery, каждая из которых содержит два поля:

  • name — имя запроса
  • query — собственно код запроса

Имя запроса является произвольной строкой. Далее указанный запрос будет вызываться именно через эту строку.

Создадим репозиторий для сущности Person. Ничего своего добавлять в репозиторий мы не будем. Нам достаточно стандартных методов:

Далее на примере тестового метода, рассмотрим, как вызвать именованный запрос по строке с его именем. Создадим следующий тестовый класс:

Обратите внимание, что бин PersonRepository автоварится только для того, чтобы сохранить первичные данные в базу в рамках теста. Для запуска именованного запроса он не требуется.

Основная смысловая нагрузка ложится на следующий участок кода:

Сначала с помощью аннотации @PersistenceContext мы получаем доступ к бину EntityManager, из которого можно извлечь именованный запрос по строке с собственно именем. Затем в этот запрос мы можем передать параметр с помощью метода setParameter(). Затем вызовом метода getResultList() мы отправляем запрос на выполнение.

Основным недостатком данного способа является необходимость использовать простую строку с именем запроса. Такую строку, конечно, желательно вынести в отдельную константу, либо вообще использоваться вызовом именованного запроса через метод репозитория.