
Méthodes de requête dérivées (Query Methods)
Découvrez comment Spring Data JPA génère automatiquement des requêtes à partir des noms de méthodes dans vos interfaces Repository (Query Methods).
La magie des requêtes sans requête
L'une des fonctionnalités les plus puissantes et les plus productives de Spring Data est sa capacité à dériver des requêtes de base de données directement à partir des noms de méthodes définies dans vos interfaces Repository. C'est ce qu'on appelle les "Query Methods" ou méthodes de requête dérivées. Fini le besoin d'écrire explicitement du JPQL ou du SQL pour de nombreuses requêtes courantes de recherche !
Le principe est simple : vous définissez une méthode dans votre interface Repository (qui étend par exemple JpaRepository) en respectant une convention de nommage spécifique, et Spring Data analyse ce nom au démarrage pour générer et exécuter automatiquement la requête JPQL correspondante lorsque cette méthode est appelée.
Cela réduit considérablement le code boilerplate, améliore la lisibilité pour les requêtes simples et offre une certaine sécurité de type, car les noms de méthodes sont vérifiés à la compilation (contrairement aux requêtes sous forme de chaînes de caractères).
Le mécanisme de dérivation : Comment ça marche ?
Spring Data analyse le nom de la méthode en le découpant en deux parties principales :
- Le préfixe (verbe) : Indique l'action de la requête. Les préfixes les plus courants sont
find...By,read...By,query...By,get...By(tous synonymes pour des requêtes de recherche), mais aussicount...By(pour compter les résultats) etexists...By(pour vérifier l'existence). Depuis Spring Data JPA 2.x,delete...Byouremove...Bysont aussi supportés pour dériver des requêtes de suppression. - Le critère (prédicat) : La partie après le premier
Bydécrit les conditions de la requête. Elle est composée des noms des propriétés de l'entité gérée par le Repository (en respectant la casse camelCase) et de mots-clés optionnels pour affiner les conditions (commeAnd,Or,LessThan,Like, etc.).
Les paramètres de la méthode doivent correspondre aux propriétés mentionnées dans la partie critère, dans le même ordre.
Par exemple, si vous avez une entité User avec une propriété String email, la méthode suivante dans votre UserRepository :
Optional findByEmail(String email); sera interprétée par Spring Data pour générer une requête JPQL équivalente à :
SELECT u FROM User u WHERE u.email = ?1où ?1 représente le premier paramètre de la méthode (email).
Mots-clés courants pour les critères
Spring Data reconnaît un grand nombre de mots-clés que vous pouvez insérer entre les noms de propriétés dans la partie critère pour construire des requêtes plus complexes :
And: Combine deux conditions avec un ET logique. Exemple:findByLastnameAndFirstname(String lastname, String firstname)Or: Combine deux conditions avec un OU logique. Exemple:findByLastnameOrFirstname(String lastname, String firstname)Is,Equals: Teste l'égalité (souvent implicite si aucun autre mot-clé n'est utilisé). Exemple:findByFirstname(String firstname)oufindByFirstnameIs(String firstname)Between: Teste si une valeur est dans un intervalle (nécessite deux paramètres). Exemple:findByStartDateBetween(LocalDate start, LocalDate end)LessThan,LessThanEqual: Inférieur à, inférieur ou égal à. Exemple:findByAgeLessThan(int age)GreaterThan,GreaterThanEqual: Supérieur à, supérieur ou égal à. Exemple:countBySalaryGreaterThanEqual(BigDecimal minSalary)After,Before: Spécifiques aux dates/heures (équivalents à GreaterThan/LessThan). Exemple:findByRegistrationDateAfter(Instant date)IsNull,IsNotNull(ouNotNull): Teste la nullité. Exemple:findByTerminationDateIsNull()Like,NotLike: Recherche de motifs textuels (utilise le caractère%de SQL). Exemple:findByNameLike(String pattern)(vous devez ajouter les%au paramètre `pattern`).StartingWith,EndingWith,Containing: Raccourcis pourLikeavec les%automatiquement ajoutés au bon endroit. Exemple:findByNameStartingWith(String prefix)génèreWHERE x.name LIKE ?1%.findDescriptionContaining(String keyword)génèreWHERE x.description LIKE %?1%.OrderBy: Spécifie le tri des résultats. Suivi du nom de la propriété et de la direction (Ascpar défaut, ouDesc). Exemple:findByCityOrderByLastnameAsc(String city)Not: Négation d'une condition simple. Exemple:findByLastnameNot(String lastname)In,NotIn: Teste si une valeur est présente (ou absente) dans une collection. Exemple:findByStatusIn(Collectionstatuses) True,False: Raccourcis pour tester des booléens. Exemple:findByActiveTrue()IgnoreCase: Peut être ajouté à la fin de conditions sur des chaînes pour ignorer la casse. Exemple:findByUsernameIgnoreCase(String username)
Expressions de propriété et traversée de relations
Vous pouvez faire référence à des propriétés imbriquées en traversant les relations définies dans vos entités JPA (@ManyToOne, @OneToOne). Utilisez le nom de la propriété de la relation suivi du nom de la propriété dans l'entité liée (la première lettre en majuscule après la propriété de relation).
Par exemple, si une entité Order a une relation @ManyToOne vers une entité Customer (nommée customer dans Order), et que Customer a une propriété String city:
// Dans OrderRepository
List findByCustomerCity(String city);
Cela générera une requête JPQL équivalente à :
SELECT o FROM Order o WHERE o.customer.city = ?1Vous pouvez enchaîner plusieurs niveaux de relations. Pour éviter les ambiguïtés avec les noms de propriétés simples, vous pouvez utiliser le caractère underscore (_) dans le nom de la méthode pour indiquer explicitement la fin d'une partie de la propriété. Cependant, Spring Data est généralement assez intelligent pour le déduire correctement.
Types de retour possibles
Les méthodes de requête dérivées peuvent retourner différents types, en fonction du nombre de résultats attendus et de vos besoins :
T(Type de l'entité) : Pour les requêtes censées retourner un résultat unique (par exemple,findByUsername). Lève une exceptionIncorrectResultSizeDataAccessExceptionsi 0 ou plus d'un résultat est trouvé.Optional: Le choix recommandé pour les requêtes à résultat unique potentiel. Retourne unOptionalvide si aucun résultat n'est trouvé, évitant ainsi les exceptions pour ce cas. Lève toujours une exception si plus d'un résultat est trouvé.List,Collection,Iterable: Pour les requêtes pouvant retourner plusieurs résultats. Retourne une collection vide si aucun résultat n'est trouvé.Page: Utilisé pour la pagination. Nécessite un paramètre de typePageabledans la méthode. Retourne les résultats de la page demandée ainsi que des informations sur le nombre total d'éléments et de pages.Slice: Similaire àPage, mais ne contient que les résultats de la tranche demandée et une indication s'il y a une tranche suivante. Plus efficace si le compte total n'est pas nécessaire. Nécessite un paramètrePageable.Stream(Java 8) : Permet de traiter les résultats sous forme de flux. Nécessite d'être exécuté dans une transaction (@Transactional) et doit être fermé explicitement (try-with-resources).- Types primitifs ou Wrappers (
long,boolean,Long,Boolean) : Pour les méthodescount...Byouexists...By.
Limiter les résultats (`Top`, `First`)
Vous pouvez limiter le nombre de résultats retournés en utilisant les mots-clés Top ou First juste après le préfixe find (ou read, get, query). Vous pouvez optionnellement spécifier un nombre après Top/First.
Exemples :
// Retourne le premier employé trouvé par ordre alphabétique du nom
Optional findFirstByOrderByLastnameAsc();
// Retourne les 5 produits les plus chers
List findTop5ByOrderByPriceDesc();
// Retourne UN utilisateur actif (le premier trouvé selon l'ordre par défaut de la BDD)
Optional findFirstByActiveTrue();
Avantages et limites
Avantages :
- Réduction du code : Elimine le besoin d'écrire du JPQL/SQL pour des requêtes simples.
- Lisibilité : Les noms de méthodes peuvent être très expressifs pour des requêtes simples à modérées.
- Sécurité de type : Les erreurs de nom de propriété sont détectées à la compilation (par l'IDE) ou au démarrage de l'application.
- Refactoring facilité : Renommer une propriété d'entité dans l'IDE peut automatiquement proposer de renommer les méthodes de requête correspondantes.
Limites :
- Complexité : Les noms de méthodes peuvent devenir très longs et difficiles à lire pour des requêtes avec de nombreux critères.
- Expressivité limitée : Ne peuvent pas exprimer toutes les subtilités de JPQL ou SQL (jointures complexes, sous-requêtes, fonctions spécifiques à la base de données, etc.).
- Performance : Bien que les requêtes générées soient généralement correctes, vous n'avez pas un contrôle direct sur la requête exacte exécutée, ce qui peut être important pour l'optimisation fine.
Pour les requêtes qui dépassent la complexité gérable par les méthodes dérivées, il est préférable d'utiliser l'annotation @Query pour définir explicitement la requête JPQL ou SQL.
En conclusion, les méthodes de requête dérivées sont un outil extrêmement puissant de Spring Data JPA qui accélère considérablement le développement en automatisant la création de requêtes courantes. Elles constituent la première approche à envisager pour définir des opérations de recherche dans vos repositories.