Сортиране с хибернация

1. Общ преглед

Тази статия илюстрира как да сортирате с хибернация , използвайки както езика за запитване за хибернация (HQL), така и API на критериите.

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. Задаване на приоритет на сортиране на нулеви стойности

По подразбиране, когато атрибутът, по който да се сортира, има нулеви стойности, RDMS трябва да реши приоритета. Тази обработка по подразбиране може да бъде заменена чрез поставяне на клауза 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. Сортиране на едно към много отношения

Нека анализираме сложен случай на сортиране: сортиране на обекти в отношение едно към много - лента, съдържаща колекция от обекти на Foo .

Ще направим това, като анотираме колекцията с анотацията Hibernate @OrderBy ; ще посочим полето, чрез което се извършва поръчката, както и посоката:

@OrderBy(clause = "NAME DESC") Set fooList = new HashSet();

Забележете аргумента на тази клауза към анотацията. Това е уникално за @OrderBy на Hibernate , в сравнение с подобна @OrderBy JPA анотация. Друга характеристика, която отличава този подход от еквивалента на JPA е, че аргументът на клаузата показва, че сортирането се извършва въз основа на колоната ИМЕ на таблицата FOO , а не на атрибута name на Foo .

Сега нека разгледаме действителното сортиране на Bars and Foos :

String hql = "FROM Bar b ORDER BY b.id"; Query query = sess.createQuery(hql);

В резултат на SQL изявление показва, че подредени 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

Едно нещо, което трябва да имате предвид, е, че не е възможно да се сортират Списъци, както беше в случая с JPA. Документацията за хибернация гласи:

„Hibernate понастоящем игнорира @OrderBy в @ElementCollection в напр. Списък. Редът на елементите е такъв, какъвто се връща от базата данни, неопределен. "

Като странична бележка е възможно да се заобиколи това ограничение, като се използва старата XML конфигурация за Hibernate и се замени елемент с a елемент.

3. Сортиране с критерии за хибернация

API на обекта на критериите предоставя клас Поръчка като основен API за управление на сортирането.

3.1. Задаване на реда за сортиране

Класът Order има два метода за задаване на реда за сортиране:

  • asc (String атрибут) : Сортира заявката по атрибут във възходящ ред.
  • desc (String атрибут) : Сортира заявката по атрибут в низходящ ред.

Нека започнем с прост пример - сортиране по един атрибут id :

Criteria criteria = sess.createCriteria(Foo.class, "FOO"); criteria.addOrder(Order.asc("id"));

Обърнете внимание, че аргументът на метода asc е чувствителен към малки и големи букви и трябва да съвпада с името на атрибута, по който да се сортира.

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 към екземпляра 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. Задаване на приоритет на сортиране на нулеви стойности

By default, when the attribute to sort by has null values, it is up to the RDMS to decide the precedence. Hibernate Criteria Object API makes it simple to change that default and place nulls at the end of an ascending ordered list:

Criteria criteria = sess.createCriteria(Foo.class, "FOO"); criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST));

Here is the underlying SQL query – with the is null then 1 else 0 clause:

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

Alternatively, we can also place the nulls at the beginning of a descending ordered list:

Criteria criteria = sess.createCriteria(Foo.class, "FOO"); criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST));

The corresponding SQL query follows – with the is null then 0 else 1 clause:

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

Note that, 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 за прости обекти, както и за обекти в отношение едно към много.

Внедряването на този урок за сортиране на хибернация може да бъде намерено в проекта github - това е проект, базиран на Eclipse, така че трябва да е лесно да се импортира и да се изпълнява както е.