Pagination JPA

Pagination JPA

1. Vue d'ensemble

Cet article explique comment implémenterpagination in the Java Persistence API.

Il explique comment effectuer une pagination avec JQL de base et avec les API basées sur des critères plus sécurisées, en discutant des avantages et des problèmes connus de chaque implémentation.

Lectures complémentaires:

Pagination avec table Spring REST et AngularJS

Un aperçu complet de la manière de mettre en œuvre une API simple avec la pagination avec Spring et de la consommer avec AngularJS et UI Grid.

Read more

Spring JPA - Plusieurs bases de données

Comment configurer Spring Data JPA pour qu'il fonctionne avec plusieurs bases de données distinctes.

Read more

Données de printemps JPA @Query

Apprenez à utiliser l'annotation @Query dans Spring Data JPA pour définir des requêtes personnalisées à l'aide de JPQL et de SQL natif.

Read more

2. Pagination avec JQL et l'APIsetFirstResult(),setMaxResults()

Le moyen le plus simple d'implémenter la pagination est d'utiliserthe Java Query Language - créez une requête et configurez-la viasetMaxResults ** etsetFirstResult:

Query query = entityManager.createQuery("From Foo");
int pageNumber = 1;
int pageSize = 10;
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List  fooList = query.getResultList();

L'API est simple:

  • *setFirstResult(int*): définit la position de décalage dans le jeu de résultats pour démarrer la pagination

  • setMaxResults(int): définit le nombre maximum d'entités à inclure dans la page

2.1. Le nombre total et la dernière page

Pour une solution de pagination plus complète, nous devrons également obtenirthe total result count:

Query queryTotal = entityManager.createQuery
    ("Select count(f.id) from Foo f");
long countResult = (long)queryTotal.getSingleResult();

Le calcul dethe last page est également très utile:

int pageSize = 10;
int pageNumber = (int) ((countResult / pageSize) + 1);

Notez que cette approche pour obtenir le nombre total de résultats nécessite une requête supplémentaire (pour le nombre).

3. Pagination avec JQL à l'aide des identifiants d'entités

Une stratégie de pagination alternative simple est defirst retrieve the full ids puis - sur la base de ces -retrieve the full entities. Cela permet un meilleur contrôle de l'extraction d'entités - mais cela signifie également qu'il faut charger toute la table pour récupérer les identifiants:

Query queryForIds = entityManager.createQuery(
  "Select f.id from Foo f order by f.lastName");
List fooIds = queryForIds.getResultList();
Query query = entityManager.createQuery(
  "Select f from Foo e where f.id in :ids");
query.setParameter("ids", fooIds.subList(0,10));
List fooList = query.getResultList();

Enfin, notez également que deux requêtes distinctes sont nécessaires pour extraire les résultats complets.

4. Pagination avec JPA à l'aide de l'API Criteria

Voyons ensuite comment nous pouvonsleverage the JPA Criteria API pour implémenter la pagination:

int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager
  .getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
TypedQuery typedQuery = entityManager.createQuery(select);
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(pageSize);
List fooList = typedQuery.getResultList();

Ceci est utile lorsque le but est de créer des requêtes dynamiques, sûres des pannes. Contrairement aux requêtes JQL ou HQL «codées en dur», «basées sur des chaînes»,JPA Criteria réduit les échecs d'exécution car le compilateur vérifie dynamiquement les erreurs de requête.

Avec les critères JPAgetting the total number of entities en assez simple:

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder.count(
  countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

Le résultat final esta full pagination solution, en utilisant l'API JPA Criteria:

int pageNumber = 1;
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

CriteriaQuery countQuery = criteriaBuilder
  .createQuery(Long.class);
countQuery.select(criteriaBuilder
  .count(countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
  .getSingleResult();

CriteriaQuery criteriaQuery = criteriaBuilder
  .createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);

TypedQuery typedQuery = entityManager.createQuery(select);
while (pageNumber < count.intValue()) {
    typedQuery.setFirstResult(pageNumber - 1);
    typedQuery.setMaxResults(pageSize);
    System.out.println("Current page: " + typedQuery.getResultList());
    pageNumber += pageSize;
}

5. Conclusion

Cet article a exploré les options de pagination de base disponibles dans JPA.

Certains présentent des inconvénients, principalement liés aux performances des requêtes, mais ils sont généralement compensés par un contrôle amélioré et une flexibilité globale.

L'implémentation de ce tutoriel Spring JPA peut être trouvée dansthe GitHub project - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.