Tri avec JPA

1. Vue d'ensemble

Cet article illustre les différentes façons dont JPA peut être utilisé pour le tri .

2. Tri avec l'API JPA / JQL

L'utilisation de JQL pour trier se fait à l'aide de la clause Order By :

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

Sur la base de cette requête, JPA génère l'instruction SQL directe suivante :

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

Notez que les mots-clés SQL de la chaîne JQL ne sont pas sensibles à la casse, mais que les noms des entités et leurs attributs le sont.

2.1. Définition de l'ordre de tri

Par défaut, l'ordre de tri est croissant , mais il peut être défini explicitement dans la chaîne JQL. Tout comme en SQL pur, les options de classement sont asc et desc :

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

La requête SQL générée inclura alors le sens de la commande:

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

2.2. Tri par plus d'un attribut

Pour trier par plusieurs attributs, ceux-ci sont ajoutés à la clause o rder by de la chaîne JQL:

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

Les deux conditions de tri apparaîtront dans l' instruction de requête SQL générée :

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. Définition de la priorité de tri des valeurs nulles

La priorité par défaut des valeurs nulles est spécifique à la base de données, mais elle est personnalisable via la clause NULLS FIRST ou NULLS LAST dans la chaîne de requête HQL.

Voici un exemple simple - classer par nom de Foo dans l'ordre décroissant et placer des Nulls à la fin:

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

La requête SQL générée inclut la clause de fin is null the 1 else 0 (3e ligne):

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. Tri des relations une à plusieurs

Au-delà des exemples de base, examinons maintenant un cas d'utilisation impliquant le tri des entités dans une relation un à plusieurs - Barre contenant une collection d' entités Foo .

Nous voulons trier les entités Bar ainsi que leur collection d' entités Foo - JPA est particulièrement simple pour cette tâche:

  1. Tri de la collection: ajoutez une annotation OrderBy précédant la collection Foo dans l' entité Bar :
    @OrderBy("name ASC") List  fooList;
  2. Tri de l'entité contenant la collection:
    String jql = "Select b from Bar as b order by b.id"; Query barQuery = entityManager.createQuery(jql); List barList = barQuery.getResultList();

Notez que l' annotation @OrderBy est facultative, mais nous l'utilisons dans ce cas car nous voulons trier la collection Foo de chaque barre .

Jetons un coup d'œil à la requête SQL envoyée au 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 première requête trie l' entité Bar parente . La deuxième requête est générée pour trier la collection d' entités Foo enfants appartenant à Bar .

3. Tri avec l'API d'objet de requête de critères JPA

Avec JPA Criteria - la méthode orderBy est une alternative «à guichet unique» pour définir tous les paramètres de tri: la direction de l' ordre et les attributs à trier peuvent être définis. Voici l'API de la méthode:

  • orderBy ( CriteriaBuilder.asc ): Trie par ordre croissant.
  • orderBy ( CriteriaBuilder.desc ): Trie par ordre décroissant.

Chaque instance Order est créée avec l' objet C riteriaBuilder via ses méthodes asc ou desc .

Voici un exemple rapide - trier les Foos par leur nom :

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

L'argument de la méthode ge t est sensible à la casse, car il doit correspondre au nom de l'attribut.

Contrairement au JQL simple, l'API JPA Criteria Query Object force une direction d'ordre explicite dans la requête. Avis dans la dernière ligne de cet extrait de code que les criteriaBuilder objet spécifie l'ordre de tri de à ascendantes en appelant sa asc méthode.

Lorsque le code ci-dessus est exécuté, JPA génère la requête SQL ci-dessous. JPA Criteria Object génère une instruction SQL avec une clause asc explicite :

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

3.1. Tri par plus d'un attribut

Pour trier par plus d'un attribut, passez simplement une instance Order à la méthode orderBy pour chaque attribut à trier.

Voici un exemple rapide - tri par nom et id , respectivement dans l'ordre asc et desc :

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 requête SQL correspondante est illustrée ci-dessous:

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

4. Conclusion

Cet article explore les alternatives de tri dans l'API Java Persistence, pour les entités simples ainsi que pour les entités dans une relation un-à-plusieurs. Ces approches délèguent la charge du travail de tri à la couche de base de données.

La mise en œuvre de ce tutoriel de tri JPA se trouve dans le projet GitHub - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.