Ordinamento con Hibernate

1. Panoramica

Questo articolo illustra come ordinare con Hibernate , utilizzando sia Hibernate Query Language (HQL) che l'API Criteria.

2. Ordinamento con HQL

Ordinare con HQL di Hibernate è semplice come aggiungere la clausola Order By alla stringa di query HQL:

String hql = "FROM Foo f ORDER BY f.name"; Query query = sess.createQuery(hql);

Dopo che questo codice è stato eseguito, Hibernate genererà la seguente query SQL:

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from FOO foo0_ order by foo0_.NAME

La direzione di ordinamento predefinita è crescente. Questo è il motivo per cui la condizione dell'ordine, asc , non è inclusa nella query SQL generata.

2.1. Utilizzo di un ordinamento esplicito

Per specificare manualmente l'ordinamento, dovrai includere la direzione dell'ordine nella stringa di query HQL :

String hql = "FROM Foo f ORDER BY f.name ASC"; Query query = sess.createQuery(hql);

In questo esempio, l'impostazione della clausola asc nell'HQL è stata inclusa nella query SQL generata:

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from FOO foo0_ order by foo0_.NAME ASC

2.2. Ordinamento per più di un attributo

È possibile aggiungere più attributi, insieme a un ordinamento opzionale, alla clausola Order By nella stringa di query HQL:

String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC"; Query query = sess.createQuery(hql);

La query SQL generata cambierà di conseguenza:

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. Impostazione della precedenza di ordinamento dei valori nulli

Per impostazione predefinita, quando l'attributo in base a cui ordinare ha valori nulli , spetta all'RDMS decidere la precedenza. Questo trattamento predefinito può essere sovrascritto inserendo una clausola NULLS FIRST o NULLS LAST nella stringa di query HQL .

Questo semplice esempio inserisce eventuali valori nulli alla fine dell'elenco dei risultati:

String hql = "FROM Foo f ORDER BY f.name NULLS LAST"; Query query = sess.createQuery(hql);

Vediamo che la clausola è nulla quindi 1 else 0 nella query SQL generata :

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. Ordinamento uno a molti rapporti

Analizziamo un caso di ordinamento complesso: ordinamento di entità in una relazione uno a molti - Barra contenente una raccolta di entità Foo .

Lo faremo annotando la raccolta con l' annotazione Hibernate @OrderBy ; specificheremo il campo con il quale viene effettuato l'ordine, nonché la direzione:

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

Si noti che l' argomento della clausola nell'annotazione. Questo è unico per @OrderBy di Hibernate , rispetto all'annotazione JPA @OrderBy simile . Un'altra caratteristica che differenzia questo approccio dal suo equivalente JPA è che l' argomento della clausola indica che l'ordinamento viene eseguito in base alla colonna NAME della tabella FOO , non sull'attributo name di Foo .

Ora diamo un'occhiata all'ordinamento effettivo di Bars e Foos :

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

L' istruzione SQL risultante mostra che i Foo ordinati vengono inseriti in un 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

Una cosa da tenere a mente è che non è possibile ordinare gli elenchi come nel caso di JPA. La documentazione di Hibernate afferma:

"Hibernate attualmente ignora @OrderBy su @ElementCollection, ad esempio su List. L'ordine degli elementi è quello restituito dal database, non definito. "

Come nota a margine, sarebbe possibile aggirare questa limitazione utilizzando la configurazione XML legacy per Hibernate e sostituendo il elemento con a elemento.

3. Ordinamento con criteri di ibernazione

L'API Criteria Object fornisce la classe Order come API principale per gestire l'ordinamento.

3.1. Impostazione dell'ordinamento

La classe Order ha due metodi per impostare l'ordinamento:

  • asc (attributo stringa) : ordina la query per attributo in ordine crescente.
  • desc (attributo stringa) : ordina la query per attributo in ordine decrescente.

Cominciamo con un semplice esempio: ordinamento in base a un singolo attributo id :

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

Si noti che l'argomento del metodo asc fa distinzione tra maiuscole e minuscole e deve corrispondere al nome dell'attributo in base al quale ordinare.

L'API Object di Hibernate Criteria imposta esplicitamente una direzione di ordinamento e questo si riflette nell'istruzione SQL generata dal codice:

Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_ from FOO this_ order by this_.ID sac

3.2. Ordinamento per più di un attributo

L'ordinamento per più attributi richiede solo l'aggiunta di un oggetto Order all'istanza Criteria , come nell'esempio seguente:

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

La query generata in 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. Impostazione della precedenza di ordinamento dei valori nulli

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.

Ad esempio, se il valore di f.anIntVariable è nullo, l'esecuzione della query:

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

lancerà:

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. Conclusione

Questo articolo esplora l'ordinamento con Hibernate, utilizzando le API disponibili per entità semplici e per entità in una relazione uno-a-molti.

L'implementazione di questo tutorial sull'ordinamento di Hibernate può essere trovata nel progetto github: questo è un progetto basato su Eclipse, quindi dovrebbe essere facile da importare ed eseguire così com'è.