Создадим именованный запрос над классом сущности, который в дальнейшем будет вызываться через специальный метод в репозитории. Именованные запросы, вызываемые через методы репозитерия, рассмотрены в другой статье.
В классе сохраняемой сущности можно объявить один или несколько запросов, дать им имена, а также сопоставить им методы в репозитории, вызывая которые, мы будем запускать эти запросы на выполнение.
Создадим минимальное Spring Boot приложение с поддержкой JPA/Hibernate.
Добавим в проект следующую сущность:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Entity @org.hibernate.annotations.NamedQueries({ @org.hibernate.annotations.NamedQuery( name = "Address.findMoscow", query = "select a from Address a where city='Москва'" ) }) public class Address { @Id @GeneratedValue private Long id; private String city; private String streetHouseApartment; //Конструкторы, геттеры и сеттеры, toString() и т.д. } |
Класс сущности помимо @Entity также помечен аннотацией @NamedQueries. Поскольку это чисто хибернейтовская аннотация, а не стандартная JPA аннотация, то по правилам приличия пишется её полное имя.
В аннотацию @NamedQueries передаётся массив аннотаций @NamedQuery, каждая из которых содержит два поля:
- name — имя запроса
- query — собственно код запроса
Причём имя запроса начинается с имени сущности, после которой через точку пишется собственно имя метода, который будет этот запрос запускать (Address.findMoscow).
Далее создадим репозиторий со следующим содержимым:
1 2 3 4 |
@Repository public interface AddressRepository extends JpaRepository<Address, Long> { List<Address> findMoscow(); } |
В репозитории мы создали метод List findMoscow(), название которого дублирует правую часть имени запроса (name = «Address.findMoscow») из аннотации @NamedQuery. Теперь, вызывая этот метод репозитория, мы будем запускать за выполнение соответствующий запрос (query = «select a from Address a where city=’Москва'»).
Создадим тест, который продемонстрирует использование именованного запроса через вызов метода репозитория. Создадим следующий тестовый класс:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@SpringBootTest public class GlobalMetaDataClassTest { @Autowired AddressRepository addressRepository; @BeforeEach void cleanTable() { addressRepository.deleteAll(); } @Test void globalMetaDataNamedQueryViaMethod() { Address msk = new Address("Москва", "Садовая, д.2"); Address spb = new Address("Санкт-Петербург", "Парковая, д.3"); addressRepository.save(msk); addressRepository.save(spb); List<Address> mskAddresses = addressRepository.findMoscow(); assertEquals(mskAddresses.size(), 1); assertEquals(mskAddresses.get(0), msk); } } |
Мы создали две сущности типа Address, у одной из которых поле city заполнили строкой «Москва», а у другой, соответственно, — «Санкт-Петербург». Вызвав метод findMoscow() репозитория, мы запустили на выполнение соответствующий запрос, определённый в классе Address. Если имя метода не будет совпадать ни с одним из имён запросов (например, мы где-то опечатаемся), то ошибка выявится на этапе запуска приложения.