Сортировка с Hibernate
1. обзор
В этой статье показанhow to Sort with Hibernate с использованием как языка запросов Hibernate (HQL), так и API критериев.
Дальнейшее чтение:
Hibernate: сохранить, сохранить, обновить, объединить, saveOrUpdate
Краткое и практическое руководство по методам записи Hibernate: сохранение, сохранение, обновление, объединение, saveOrUpdate.
Удаление объектов с помощью Hibernate
Краткое руководство по удалению сущности в Hibernate.
Hibernate Перехватчики
Краткое и практическое руководство по созданию перехватчиков Hibernate.
2. Сортировка с HQL
Сортировка с помощью Hibernate HQL так же проста, как добавление предложенияOrder By в строку запроса HQL:
String hql = "FROM Foo f ORDER BY f.name";
Query query = sess.createQuery(hql);
После выполнения этого кода Hibernate сгенерирует следующий SQL-запрос:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from
FOO foo0_ order by foo0_.NAME
Направление сортировки по умолчанию - восходящее. Вот почему условие порядкаasc не включается в сгенерированный SQL-запрос.
2.1. Использование явного порядка сортировки
Чтобы указать порядок сортировки вручную, вам необходимо указать направление сортировки в строке запросаHQL:
String hql = "FROM Foo f ORDER BY f.name ASC";
Query query = sess.createQuery(hql);
В этом примере установка предложенияasc в HQL была включена в сгенерированный запрос SQL:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
from FOO foo0_ order by foo0_.NAME ASC
2.2. Сортировка по более чем одному атрибуту
К предложениюOrder By в строке запроса HQL можно добавить несколько атрибутов вместе с необязательным порядком сортировки:
String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC";
Query query = sess.createQuery(hql);
Сгенерированный запрос SQL изменится соответственно:
Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
from FOO foo0_ order by foo0_.NAME DESC, foo0_.ID ASC
2.3. Установка приоритета сортировки нулевых значений
По умолчанию, когда атрибут для сортировки имеет значенияnull, решение о приоритете принимает RDMS. Эту процедуру по умолчанию можно изменить, поместивa NULLS FIRST or NULLS LAST clause in the HQL query string.
Этот простой пример помещает любые нули в конец списка результатов:
String hql = "FROM Foo f ORDER BY f.name NULLS LAST";
Query query = sess.createQuery(hql);
Давайте посмотрим предложениеis null then 1 else 0 вgenerated SQL query:
Hibernate: select foo0_.ID as ID1_1_, foo0_.NAME as NAME2_1_,
foo0_.BAR_ID as BAR_ID3_1_, foo0_.idx as idx4_1_ from FOO foo0_
order by case when foo0_.NAME is null then 1 else 0 end, foo0_.NAME
2.4. Сортировка отношений один ко многим
Давайте проанализируем сложный случай сортировки:sorting entities in a one to many relation -Bar, содержащий набор сущностейFoo.
Мы сделаем это, аннотируя коллекцию с помощьюthe Hibernate @OrderBy annotation; мы укажем поле, по которому производится заказ, а также направление:
@OrderBy(clause = "NAME DESC")
Set fooList = new HashSet();
Обратите внимание на аргументclause аннотации. Это уникально для@OrderBy Hibernate по сравнению с аналогичной аннотацией JPA@OrderBy. Еще одна характеристика, которая отличает этот подход от его эквивалента в JPA, заключается в том, что аргументclause указывает, что сортировка выполняется на основе столбцаNAME таблицыFOO, а неname атрибутFoo.
Теперь давайте посмотрим на фактическую сортировкуBars иFoos:
String hql = "FROM Bar b ORDER BY b.id";
Query query = sess.createQuery(hql);
resulting SQL statement показывает, что отсортированныеFoo’s помещаются вfooList:
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_ID3_0_0_,
foolist0_.ID as ID1_1_0_, foolist0_.ID as ID1_1_1_, foolist0_.NAME as
NAME2_1_1_, foolist0_.BAR_ID as BAR_ID3_1_1_, foolist0_.idx as idx4_1_1_
from FOO foolist0_ where foolist0_.BAR_ID=? order by foolist0_.NAME desc
Следует иметь в виду, что этоnot possible to to sort Lists, как в случае с JPA. Документация Hibernate гласит:
«В настоящее время Hibernate игнорирует @OrderBy в @ElementCollection, например, в List
. Порядок элементов такой же, как и в базе данных, не определен ».
В качестве примечания, можно было бы обойти это ограничение, используя устаревшую конфигурацию XML для Hibernate и заменив элемент<List..> на элемент<Bag…>.
3. Сортировка по критериям гибернации
API объекта критериев предоставляет классOrder в качестве основного API для управления сортировкой.
3.1. Установка порядка сортировки
У классаOrder есть два метода для установки порядка сортировки:
-
*asc*(String attribute): сортирует запрос поattribute в порядке возрастания.
-
*desc*(String attribute): сортирует запрос поattribute в порядке убывания.
Начнем с простого примера - сортировки по одному атрибутуid:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("id"));
Обратите внимание, что аргумент методаasc чувствителен к регистру и должен соответствоватьname атрибута для сортировки.
Object API Hibernate Criteria явно устанавливает направление сортировки, и это отражается в операторе SQL, сгенерированном кодом:
Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_
from FOO this_ order by this_.ID sac
3.2. Сортировка по более чем одному атрибуту
Для сортировки по нескольким атрибутам требуется только добавить объектOrder к экземпляруCriteria, как в примере ниже:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name"));
criteria.addOrder(Order.asc("id"));
Запрос, который генерируется в SQL:
Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_ from
FOO this_ order by this_.NAME asc, this_.ID sac
3.3. Установка приоритета сортировки нулевых значений
По умолчанию, когда атрибут для сортировки имеет значенияnull, решение о приоритете принимает RDMS. Hibernate Criteria Object API упрощает изменение этого значения по умолчанию иplace nulls at the end в возрастающем упорядоченном списке:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST));
Вот базовый запросSQL - с предложениемis null then 1 else 0:
Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
this_.NAME is null then 1 else 0 end, this_.NAME asc
В качестве альтернативы мы также можемplace the nulls at the beginning упорядоченного по убыванию списка:
Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST));
Соответствующий запрос SQL следует с предложениемis null then 0 else 1:
Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
this_.NAME is null then 0 else 1 end, this_.NAME desc
Отметим, чтоif the attribute to sort by is a primitive type like an int, a PresisitenceException will thrown.
Например, если значениеf.anIntVariable равно нулю, то выполнение запроса:
String jql = "Select f from Foo as f order by f.anIntVariable desc NULLS FIRST";
Query sortQuery = entityManager.createQuery(jql);
скину
javax.persistence.PersistenceException: org.hibernate.PropertyAccessException:
Null value was assigned to a property of primitive type setter of
com.cc.jpa.example.Foo.anIntVariable
4. Заключение
В этой статье рассматривается сортировка с помощью Hibernate - использование доступных API-интерфейсов для простых сущностей, а также для сущностей в отношении «один ко многим».
Реализацию этого руководства по сортировке Hibernate можно найти вthe github project - это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.