Перейти к основному содержимому

Сортировка с помощью JPA

· 5 мин. чтения

1. Обзор

В этой статье показаны различные способы использования JPA для сортировки .

2. Сортировка с помощью JPA/JQL API

Использование JQL для сортировки осуществляется с помощью предложения Order By :

String jql ="Select f from Foo as f order by f.id";
Query query = entityManager.createQuery (jql);

На основе этого запроса JPA генерирует следующую простую инструкцию SQL :

Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ 
from Foo foo0_ order by foo0_.id

Обратите внимание, что ключевые слова SQL в строке JQL не чувствительны к регистру, в отличие от имен сущностей и их атрибутов.

2.1. Установка порядка сортировки

По умолчанию порядок сортировки — по возрастанию , но его можно явно задать в строке JQL. Так же, как и в чистом SQL, параметры порядка asc и desc :

String jql = "Select f from Foo as f order by f.id desc";
Query sortQuery = entityManager.createQuery(jql);

Затем сгенерированный SQL-запрос будет включать направление заказа:

Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ 
from Foo foo0_ order by foo0_.id desc

2.2. Сортировка по более чем одному атрибуту

Для сортировки по нескольким атрибутам они добавляются в предложение order by строки JQL:

String jql ="Select f from Foo as f order by f.name asc, f.id desc";
Query sortQuery = entityManager.createQuery(jql);

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

Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ 
from Foo foo0_ order by foo0_.name asc, foo0_.id desc

2.3. Настройка приоритета сортировки нулевых значений

Приоритет значений NULL по умолчанию зависит от базы данных, но его можно настроить с помощью предложения NULLS FIRST или NULLS LAST в строке запроса HQL.

Вот простой пример — упорядочивание по имени Foo в порядке убывания и размещение Null в конце:

Query sortQuery = entityManager.createQuery
("Select f from Foo as f order by f.name desc NULLS LAST");

Генерируемый SQL-запрос включает в себя завершающее предложение is null the 1 else 0 (3-я строка):

Hibernate: select foo0_.id as id1_4_, foo0_.BAR_ID as BAR_ID2_4_, 
foo0_.bar_Id as bar_Id2_4_, foo0_.name as name3_4_,from Foo foo0_ order
by case when foo0_.name is null then 1 else 0 end, foo0_.name desc

2.4. Сортировка отношений «один ко многим»

Пропустив основные примеры, давайте теперь рассмотрим вариант использования, включающий сортировку сущностей в отношении один ко многимBar , содержащий коллекцию сущностей Foo .

Мы хотим отсортировать объекты Bar , а также их набор объектов Foo — JPA особенно прост для этой задачи:

  1. Сортировка коллекции: добавьте аннотацию OrderBy перед коллекцией Foo в объекте Bar :
@OrderBy("name ASC")
List <Foo> fooList;
  1. Сортировка сущности, содержащей коллекцию:
String jql = "Select b from Bar as b order by b.id";
Query barQuery = entityManager.createQuery(jql);
List<Bar> barList = barQuery.getResultList();

Обратите внимание, что аннотация @OrderBy необязательна, но мы используем ее в этом случае, потому что хотим отсортировать коллекцию Foo каждого Bar .

Давайте посмотрим на SQL-запрос , отправленный в RDMS:

Hibernate: select bar0_.id as id1_0_, bar0_.name as name2_0_ from Bar bar0_ order by bar0_.id

Hibernate:
select foolist0_.BAR_ID as BAR_ID2_0_0_, foolist0_.id as id1_4_0_,
foolist0_.id as id1_4_1_, foolist0_.BAR_ID as BAR_ID2_4_1_,
foolist0_.bar_Id as bar_Id2_4_1_, foolist0_.name as name3_4_1_
from Foo foolist0_
where foolist0_.BAR_ID=? order by foolist0_.name asc

Первый запрос сортирует родительский объект Bar . Второй запрос генерируется для сортировки коллекции дочерних сущностей Foo , принадлежащих Bar .

3. Сортировка с помощью JPA Criteria Query Object API

С критериями JPA метод orderBy является универсальной альтернативой для установки всех параметров сортировки: можно установить как направление заказа, так и атрибуты для сортировки . Ниже приведен API метода:

  • orderBy ( CriteriaBuilder.asc ): сортирует по возрастанию.
  • orderBy ( CriteriaBuilder.desc ): сортирует по убыванию.

Каждый экземпляр Order создается с помощью объекта C riteriaBuilder с помощью его методов asc или desc .

Вот быстрый пример — сортировка Foos по имени :

CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")));

Аргумент метода get чувствителен к регистру, поскольку он должен соответствовать имени атрибута.

В отличие от простого JQL, JPA Criteria Query Object API задает явное направление порядка в запросе. Обратите внимание, что в последней строке этого фрагмента кода объект критерияBuilder указывает порядок сортировки по возрастанию, вызывая его метод asc .

Когда приведенный выше код выполняется, JPA генерирует SQL-запрос, показанный ниже. Объект JPA Criteria генерирует оператор SQL с явным предложением asc :

Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc

3.1. Сортировка по более чем одному атрибуту

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

Вот быстрый пример — сортировка по имени и идентификатору в порядке возрастания и убывания соответственно:

CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")),
criteriaBuilder.desc(from.get("id")));

Соответствующий SQL-запрос показан ниже:

Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ 
from Foo foo0_ order by foo0_.name asc, foo0_.id desc

4. Вывод

В этой статье рассматриваются альтернативы сортировки в Java Persistence API для простых сущностей, а также для сущностей в отношении «один ко многим». Эти подходы делегируют бремя работы по сортировке на уровень базы данных.

Реализацию этого учебного пособия по сортировке JPA можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.