Types de requêtes JPA

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons les différents types de requêtes JPA. De plus, nous nous concentrerons sur la comparaison des différences entre eux et sur les avantages et les inconvénients de chacun.

2. Configuration

Tout d'abord, définissons la classe UserEntity que nous utiliserons pour tous les exemples de cet article:

@Table(name = "users") @Entity public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

Il existe trois types de requêtes JPA de base:

  • Requête , écrite dans la syntaxe JPQL (Java Persistence Query Language)
  • NativeQuery , écrit dans la syntaxe SQL simple
  • Requête d'API de critères , construite par programmation via différentes méthodes

Explorons-les.

3. Requête

Une requête a une syntaxe similaire à SQL et elle est généralement utilisée pour effectuer des opérations CRUD:

public UserEntity getUserByIdWithPlainQuery(Long id) { Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); jpqlQuery.setParameter("id", id); return (UserEntity) jpqlQuery.getSingleResult(); }

Cette requête récupère l'enregistrement correspondant de la table users et le mappe également à l' objet UserEntity .

Il existe deux sous-types de requêtes supplémentaires :

  • Requête typée
  • Requête nommée

Voyons-les en action.

3.1. Requête typée

Nous devons prêter attention à la déclaration de retour dans notre exemple précédent. JPA ne peut pas déduire le type de résultat de la requête et, par conséquent, nous devons effectuer un cast.

Mais, JPA fournit un sous-type de requête spécial appelé TypedQuery. Ceci est toujours préférable si nous connaissons au préalable notre type de résultat de requête . De plus, cela rend notre code beaucoup plus fiable et plus facile à tester.

Voyons une alternative TypedQuery , par rapport à notre premier exemple:

public UserEntity getUserByIdWithTypedQuery(Long id) { TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); typedQuery.setParameter("id", id); return typedQuery.getSingleResult(); }

De cette façon, nous obtenons une frappe plus puissante gratuitement, évitant ainsi d'éventuelles exceptions de casting.

3.2. Requête nommée

Bien que nous puissions définir dynamiquement une requête sur des méthodes spécifiques, elles peuvent éventuellement devenir une base de code difficile à maintenir. Et si nous pouvions conserver les requêtes d'utilisation générale dans un seul endroit centralisé et facile à lire?

JPA nous a également couvert à ce sujet avec un autre sous-type de requête connu sous le nom de NamedQuery.

Nous définissons NamedQuery sur la classe Entity elle-même, fournissant un moyen centralisé, rapide et facile de lire et de trouver les requêtes associées à Entity .

Toutes les NamedQueries doivent avoir un nom unique.

Voyons comment nous pouvons ajouter un NamedQuery à notre classe UserEntity :

@Table(name = "users") @Entity @NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

L' annotation @NamedQuery doit être regroupée dans une annotation @NamedQueries si nous utilisons Java avant la version 8. À partir de Java 8, nous pouvons simplement répéter l' annotation @NamedQuery dans notre classe Entity .

L'utilisation d'un NamedQuery est très simple:

public UserEntity getUserByIdWithNamedQuery(Long id) { Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); namedQuery.setParameter("userId", id); return (UserEntity) namedQuery.getSingleResult(); }

4. NativeQuery

Un NativeQuery est simplement une requête SQL. Celles-ci nous permettent de libérer toute la puissance de notre base de données, car nous pouvons utiliser des fonctionnalités propriétaires non disponibles dans la syntaxe JPQL restreinte.

Cela a un coût. Nous perdons la portabilité de la base de données de notre application avec NativeQuery car notre fournisseur JPA ne peut plus extraire des détails spécifiques de l'implémentation de la base de données ou du fournisseur.

Voyons comment utiliser un NativeQuery qui donne les mêmes résultats que nos exemples précédents:

public UserEntity getUserByIdWithNativeQuery(Long id) { Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); nativeQuery.setParameter("userId", id); return (UserEntity) nativeQuery.getSingleResult(); }

Nous devons toujours considérer si un NativeQuery est la seule option. La plupart du temps, une bonne requête JPQL peut répondre à nos besoins et, surtout, maintenir un niveau d'abstraction par rapport à l'implémentation réelle de la base de données.

Utiliser NativeQuery ne signifie pas nécessairement nous verrouiller sur un fournisseur de base de données spécifique. Après tout, si nos requêtes n'utilisent pas de commandes SQL propriétaires et n'utilisent qu'une syntaxe SQL standard, le changement de fournisseur ne devrait pas être un problème.

5. Requête API de critères

Les requêtes de l'API Criteria sont des requêtes de type sécurisées construites par programme - un peu similaires aux requêtes JPQL dans la syntaxe:

public UserEntity getUserByIdWithCriteriaQuery(Long id) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) .where(criteriaBuilder.equal(userRoot.get("id"), id))) .getSingleResult(); return queryResult; }

Il peut être intimidant d'utiliser les requêtes de l'API Criteria de première main, mais elles peuvent être un excellent choix lorsque nous devons ajouter des éléments de requête dynamiques ou lorsqu'ils sont associés au métamodèle JPA .

6. Conclusion

Dans cet article rapide, nous avons appris ce que sont les requêtes JPA, ainsi que leur utilisation.

Les requêtes JPA sont un excellent moyen d'abstraire notre logique métier de notre couche d'accès aux données car nous pouvons nous appuyer sur la syntaxe JPQL et laisser notre fournisseur JPA de choix gérer la traduction des requêtes .

Tout le code présenté dans cet article est disponible à l'adresse over sur GitHub.