Автор оригинала: Eugen Paraschiv.
1. Обзор
Эта статья иллюстрирует как сортировать с помощью Hibernate , используя как язык запросов Hibernate (HQL), так и API критериев.
Дальнейшее чтение:
Hibernate: сохранение, сохранение, обновление, слияние, saveOrUpdate
Удаление объектов с помощью Hibernate
Спящие перехватчики
2. Сортировка С Помощью HQL
Сортировка с помощью HQL Hibernate так же проста, как добавление предложения 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 или NULLS LAST в строку запроса HQL .
Этот простой пример помещает любые нули в конец списка результатов:
String hql = "FROM Foo f ORDER BY f.name NULLS LAST"; Query query = sess.createQuery(hql);
Давайте посмотрим, что is null then 1 else 0 предложение в сгенерированном SQL-запросе :
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. Сортировка От Одного Ко Многим Отношениям
Давайте проанализируем сложный случай сортировки: сортировка сущностей в отношении один ко многим – Bar , содержащем коллекцию сущностей Foo .
Мы сделаем это, аннотируя коллекцию с помощью Hibernate @OrderBy annotation ; мы укажем поле, по которому выполняется заказ, а также направление:
@OrderBy(clause = "NAME DESC") SetfooList = new HashSet();
Обратите внимание, что предложение аргумент аннотации. Это уникально для Hibernate @OrderBy , по сравнению с аналогичной аннотацией @OrderBy JPA. Еще одна характеристика, отличающая этот подход от его эквивалента GPA, заключается в том, что аргумент clause указывает, что сортировка выполняется на основе столбца NAME таблицы FOO , а не на атрибуте name таблицы Foo .
Теперь давайте посмотрим на фактическую сортировку Баров и Еды :
String hql = "FROM Bar b ORDER BY b.id"; Query query = sess.createQuery(hql);
Результирующий SQL-оператор показывает, что сортированные Foo помещаются в глупый:
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
Следует иметь в виду, что сортировка списков невозможна, как это было в случае с JPA. Состояния документации Hibernate:
“Hibernate в настоящее время игнорирует @OrderBy на @ElementCollection, например, List. Порядок элементов, возвращаемый базой данных, не определен.”
В качестве дополнительного замечания можно было бы обойти это ограничение, используя устаревшую конфигурацию XML для Hibernate и заменив элемент с <Сумка…> элемент.
3. Сортировка По Критериям Hibernate
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 атрибута для сортировки.
Hibernate Criteries Object API явно задает направление порядка сортировки, и это отражается в 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 в экземпляр Criteries , как в приведенном ниже примере:
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 Criteries Object API упрощает изменение этого значения по умолчанию и помещает нули в конец упорядоченного по возрастанию списка:
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
В качестве альтернативы мы также можем поместить нули в начало нисходящего упорядоченного списка:
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
Обратите внимание, что если атрибут для сортировки является примитивным типом, таким как int, a Persistenceexception будет брошен .
Например, если значение f.an Int переменная имеет значение null, то выполнение запроса:
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 можно найти в проекте github – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.