Ordinamento con JPA

1. Panoramica

Questo articolo illustra i vari modi in cui JPA può essere utilizzato per l'ordinamento .

2. Ordinamento con API JPA / JQL

L'utilizzo di JQL per l'ordinamento viene eseguito con l'aiuto della clausola Order By :

String jql; Query query = entityManager.createQuery (jql);

Sulla base di questa query, JPA genera la seguente istruzione SQL diretta :

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

Notare che le parole chiave SQL nella stringa JQL non fanno distinzione tra maiuscole e minuscole, ma lo sono i nomi delle entità e dei loro attributi.

2.1. Impostazione dell'ordinamento

Per impostazione predefinita, l'ordinamento è crescente , ma può essere impostato esplicitamente nella stringa JQL. Proprio come in SQL puro, le opzioni di ordinamento sono asc e desc :

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

La query SQL generata includerà quindi la direzione dell'ordine:

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

2.2. Ordinamento per più di un attributo

Per ordinare in base a più attributi, questi vengono aggiunti alla clausola o rder by della stringa JQL:

String jql; Query sortQuery = entityManager.createQuery(jql);

Entrambe le condizioni di ordinamento appariranno nell'istruzione della query SQL generata :

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

La precedenza predefinita di null è specifica del database, ma è personalizzabile tramite la clausola NULLS FIRST o NULLS LAST nella stringa di query HQL.

Ecco un semplice esempio: ordinare per nome di Foo in ordine decrescente e inserire Null alla fine:

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

La query SQL generata include la clausola finale 1 else 0 (3a riga):

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

Andando oltre gli esempi di base, esaminiamo ora un caso d'uso che coinvolge l' ordinamento di entità in una relazione uno a molti - Barra contenente una raccolta di entità Foo .

Vogliamo ordinare le entità Bar e anche la loro raccolta di entità Foo - JPA è particolarmente semplice per questa attività:

  1. Ordinamento della raccolta: aggiungere un'annotazione OrderBy prima della raccolta Foo nell'entità Bar :
    @OrderBy("name ASC") List  fooList;
  2. Ordinamento dell'entità contenente la raccolta:
    String jql = "Select b from Bar as b order by b.id"; Query barQuery = entityManager.createQuery(jql); List barList = barQuery.getResultList();

Nota che l' annotazione @OrderBy è facoltativa, ma la stiamo usando in questo caso perché vogliamo ordinare la raccolta Foo di ogni Bar .

Diamo un'occhiata alla query SQL inviata all'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 

La prima query ordina l' entità Bar padre . La seconda query viene generata per ordinare la raccolta di entità Foo figlio appartenenti a Bar .

3. Ordinamento con criteri JPA Query Object API

Con i criteri JPA, il metodo orderBy è un'alternativa "one stop" per impostare tutti i parametri di ordinamento: è possibile impostare sia la direzione dell'ordine che gli attributi in base ai quali ordinare . Di seguito è riportata l'API del metodo:

  • orderBy(CriteriaBuilder.asc): Sorts in ascending order.
  • orderBy(CriteriaBuilder.desc): Sorts in descending order.

Each Order instance is created with the CriteriaBuilder object through its asc or desc methods.

Here is a quick example – sorting Foos by their name:

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

The argument to the get method is case sensitive, since it needs to match the name of the attribute.

As opposed to simple JQL, the JPA Criteria Query Object API forces an explicit order direction in the query. Notice in the last line of this code snippet that the criteriaBuilder object specifies the sorting order to be ascending by calling its asc method.

When the above code is executed, JPA generates the SQL query shown below. JPA Criteria Object generates an SQL statement with an explicit asc clause:

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

3.1. Sorting by More Than One Attribute

To sort by more than one attribute simply pass an Order instance to the orderBy method for each attribute to sort by.

Ecco un rapido esempio: ordinamento per nome e ID , rispettivamente in ordine asc e disc :

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

La query SQL corrispondente è mostrata di seguito:

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

4. Conclusione

Questo articolo esplora le alternative di ordinamento nell'API Java Persistence, sia per entità semplici che per entità in una relazione uno-a-molti. Questi approcci delegano l'onere del lavoro di ordinamento al livello del database.

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