Выборка и сортировка данных отображаемых коллекций оператором ORDER BY вызываемым аннотацией @org.hibernate.annotations.OrderBy

Если отображаемый класс содержит поле типа коллекции, поддерживающей порядок элементов, например, List<String> emails, то с помощью аннотации @org.hibernate.annotations.OrderBy можно указать Hibernate’у добавлять в конец запроса на выборку выражение ORDER BY… с произвольным правилом сортировки. В результате данные в такую коллекцию попадут отсортированными ещё в БД.

Отметим, что это произвольное правило может содержать функции БД и вообще практически любой произвольный SQL, что может сделать такой подход зависимым от вендора СУБД.

Подготовка

Создадим базовое веб-приложения на связке Spring Boot 3 + Hibernate + PostgreSQL

Убедитесь, что файле /src/main/resources/application.properties есть следующая строка, позволяющая Hibernate’у автоматически создавать (и обновлять) схему БД при запуске приложения на основании аннотаций в классах предметной области:

spring.jpa.hibernate.ddl-auto=update

Также добавим в application.properties настройку, позволяющую видеть создаваемый Hibernate’ом SQL в консоли:

spring.jpa.show-sql=true

Код

Создадим класс предметной области, содержащий поле типа List<String>:

Мы помечаем поле List<String> emails аннотацией @org.hibernate.annotations.OrderBy с параметром clause, в который передаём выражение, которое должно быть использовано для сортировки данных в БД. Выражение может быть произвольным, но если в нём использовать специфические для конкретной СУБД функции, то это негативно скажется на переносимости приложения.

В нашем случае мы используем выражение EMAILS DESC, чтобы данные этого поля были отсортированы в обратном порядке.

Создадим репозиторий с кастомным запросом, который будет делать выборку из двух таблиц: PERSON и из связанной с ней таблицы EMAILS:

Напишем тест, который продемонстрирует работу нашего кода:

Мы сохраняем объект irina в БД, предварительно заполнив список List<String> emails адресами электронной почты в алфавитом порядке. После выборки этих данных из БД мы видим, что они оказываются отсортированными в порядке обратном алфавитному.

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

select p1_0.id,e1_0.person_id,e1_0.email,p1_0.name
from person p1_0 left join emails e1_0 on p1_0.id=e1_0.person_id
where p1_0.id=?
order by e1_0.email desc

В созданном для выборке данных запросы мы видим, что Hibernate добавил выражение order by e1_0.email desc, что соответствует нашему выражению, переданному в аннотацию @org.hibernate.annotations.OrderBy. Таким образом, сортировка данных произошла в БД.

Сравним порядок полученных данных с тем, как они хранятся в БД:

В БД, как мы и ожидали, данные хранятся в алфавитном порядке. Но при выборке срабатывает выражение из нашей аннотации и получаем мы их в обратном порядке.