Chapitre 1: Conventions de Nommage Avancées
Introduction
Dans le Module 2, vous avez appris 3 mots-clés simples: findBy, And, Or.
Maintenant, vous allez apprendre 15+ mots-clés supplémentaires pour créer des requêtes complexes!
Ce que vous allez apprendre
- Les 15+ mots-clés de Spring Data JPA
- Comment les combiner
- Des exemples pour chaque mot-clé
Durée: 1h
Comment Ça Marche?
Principe Magique de Spring Data JPA
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByPriceLessThan(Double maxPrice);
// ^^^^^^ ^^^^^ ^^^^^^^
// find By PriceLessThan
}
Spring lit le nom de la méthode et génère le SQL automatiquement!
-- SQL généré automatiquement:
SELECT * FROM product WHERE price < ?
Vous n'écrivez PAS de SQL, Spring le fait pour vous!
Structure des Noms de Méthodes
findBy + [Champ] + [Opération] + [AutreChamp] + [Opération]
Exemples:
findByName // WHERE name = ?
findByPriceLessThan // WHERE price < ?
findByNameAndPrice // WHERE name = ? AND price = ?
findByPriceBetween // WHERE price BETWEEN ? AND ?
Les 15+ Mots-Clés
1. And / Or (Vous connaissez déjà)
Combiner plusieurs conditions:
// AND
List<Product> findByNameAndPrice(String name, Double price);
// SQL: WHERE name = ? AND price = ?
// OR
List<Product> findByNameOrCategory(String name, String category);
// SQL: WHERE name = ? OR category = ?
Exemple concret:
// Trouver un produit "Laptop" à 999.99€
productRepo.findByNameAndPrice("Laptop", 999.99);
2. Between (Entre deux valeurs)
Trouver des valeurs dans un intervalle:
List<Product> findByPriceBetween(Double min, Double max);
// SQL: WHERE price BETWEEN ? AND ?
Exemple:
// Produits entre 100€ et 500€
List<Product> products = productRepo.findByPriceBetween(100.0, 500.0);
Cas d'usage:
- Prix dans une fourchette
- Dates entre deux moments
- Ages entre min et max
3. LessThan / GreaterThan (Comparaisons)
Comparer des valeurs numériques ou dates:
// Inférieur à
List<Product> findByPriceLessThan(Double maxPrice);
// SQL: WHERE price < ?
// Inférieur ou égal
List<Product> findByPriceLessThanEqual(Double maxPrice);
// SQL: WHERE price <= ?
// Supérieur à
List<Product> findByPriceGreaterThan(Double minPrice);
// SQL: WHERE price > ?
// Supérieur ou égal
List<Product> findByPriceGreaterThanEqual(Double minPrice);
// SQL: WHERE price >= ?
Exemples:
// Produits à moins de 100€
productRepo.findByPriceLessThan(100.0);
// Produits à 100€ ou moins
productRepo.findByPriceLessThanEqual(100.0);
// Produits à plus de 1000€
productRepo.findByPriceGreaterThan(1000.0);
Cas d'usage:
- Prix min/max
- Stock minimum
- Age minimum/maximum
- Dates avant/après
4. Like / Containing / StartingWith / EndingWith (Recherche Texte)
Rechercher dans des chaînes de caractères:
// LIKE (vous fournissez les %)
List<Product> findByNameLike(String pattern);
// SQL: WHERE name LIKE ?
// Utilisation: findByNameLike("%Laptop%")
// CONTAINING (Spring ajoute les % automatiquement)
List<Product> findByNameContaining(String keyword);
// SQL: WHERE name LIKE ?
// Utilisation: findByNameContaining("Laptop")
// Cherche: %Laptop%
// STARTING WITH (cherche au début)
List<Product> findByNameStartingWith(String prefix);
// SQL: WHERE name LIKE ?
// Utilisation: findByNameStartingWith("Mac")
// Cherche: Mac%
// ENDING WITH (cherche à la fin)
List<Product> findByNameEndingWith(String suffix);
// SQL: WHERE name LIKE ?
// Utilisation: findByNameEndingWith("Pro")
// Cherche: %Pro
Exemples:
// Produits contenant "phone" (iPhone, smartphone, etc.)
productRepo.findByNameContaining("phone");
// Produits commençant par "Mac" (MacBook, Mac Mini, etc.)
productRepo.findByNameStartingWith("Mac");
// Produits finissant par "Pro" (MacBook Pro, iPad Pro, etc.)
productRepo.findByNameEndingWith("Pro");
Différence Like vs Containing:
// Like - vous contrôlez les %
findByNameLike("%Laptop%") // Contient Laptop
findByNameLike("Laptop%") // Commence par Laptop
findByNameLike("%Laptop") // Finit par Laptop
// Containing - Spring ajoute les %
findByNameContaining("Laptop") // Contient Laptop (%Laptop%)
5. In / NotIn (Dans une liste)
Vérifier si une valeur est dans une liste:
// IN
List<Product> findByCategoryIn(List<String> categories);
// SQL: WHERE category IN (?, ?, ?)
// NOT IN
List<Product> findByCategoryNotIn(List<String> categories);
// SQL: WHERE category NOT IN (?, ?, ?)
Exemples:
// Produits dans plusieurs catégories
List<String> categories = Arrays.asList("Electronics", "Computers", "Phones");
productRepo.findByCategoryIn(categories);
// Produits PAS dans ces catégories
productRepo.findByCategoryNotIn(categories);
Cas d'usage:
- Filtrer par plusieurs catégories
- Exclure certains statuts
- Rechercher par plusieurs IDs
6. IsNull / IsNotNull (Valeurs nulles)
Vérifier si un champ est null:
// IS NULL
List<Product> findByDiscountIsNull();
// SQL: WHERE discount IS NULL
// IS NOT NULL (ou NotNull)
List<Product> findByDiscountIsNotNull();
List<Product> findByDiscountNotNull();
// SQL: WHERE discount IS NOT NULL
Exemples:
// Produits sans réduction
productRepo.findByDiscountIsNull();
// Produits avec une réduction
productRepo.findByDiscountIsNotNull();
Cas d'usage:
- Produits sans image
- Commandes sans date de livraison
- Utilisateurs sans email
7. True / False (Booléens)
Vérifier des valeurs booléennes:
// TRUE
List<Product> findByActiveTrue();
// SQL: WHERE active = true
// FALSE
List<Product> findByActiveFalse();
// SQL: WHERE active = false
Exemples:
// Produits actifs
productRepo.findByActiveTrue();
// Produits inactifs
productRepo.findByActiveFalse();
Cas d'usage:
- Produits actifs/inactifs
- Utilisateurs vérifiés/non vérifiés
- Commandes payées/non payées
8. IgnoreCase (Ignorer la casse)
Recherche insensible à la casse:
// Un seul champ
List<Product> findByNameIgnoreCase(String name);
// SQL: WHERE UPPER(name) = UPPER(?)
// Plusieurs champs
List<Product> findByNameAndCategoryAllIgnoreCase(String name, String category);
// SQL: WHERE UPPER(name) = UPPER(?) AND UPPER(category) = UPPER(?)
Exemples:
// Trouve "laptop", "LAPTOP", "Laptop", etc.
productRepo.findByNameIgnoreCase("laptop");
Cas d'usage:
- Recherche utilisateur (insensible à la casse)
- Recherche produit
- Email (john@email.com = JOHN@email.com)
9. OrderBy (Tri)
Trier les résultats:
// Tri ascendant
List<Product> findByCategoryOrderByPriceAsc(String category);
// SQL: WHERE category = ? ORDER BY price ASC
// Tri descendant
List<Product> findByCategoryOrderByPriceDesc(String category);
// SQL: WHERE category = ? ORDER BY price DESC
// Tri multiple
List<Product> findByCategoryOrderByPriceAscNameDesc(String category);
// SQL: WHERE category = ? ORDER BY price ASC, name DESC
Exemples:
// Laptops du moins cher au plus cher
productRepo.findByCategoryOrderByPriceAsc("Laptops");
// Laptops du plus cher au moins cher
productRepo.findByCategoryOrderByPriceDesc("Laptops");
Combinaisons Puissantes
Exemple 1: Recherche Complexe E-commerce
public interface ProductRepository extends JpaRepository<Product, Long> {
// Produits actifs, dans une fourchette de prix, triés par nom
List<Product> findByActiveTrueAndPriceBetweenOrderByNameAsc(
Double minPrice,
Double maxPrice
);
// SQL: WHERE active = true
// AND price BETWEEN ? AND ?
// ORDER BY name ASC
}
Utilisation:
// Produits actifs entre 100€ et 500€, triés par nom
productRepo.findByActiveTrueAndPriceBetweenOrderByNameAsc(100.0, 500.0);
Exemple 2: Gestion de Stock
public interface ProductRepository extends JpaRepository<Product, Long> {
// Produits en rupture de stock dans une catégorie
List<Product> findByCategoryAndStockLessThan(String category, Integer minStock);
// SQL: WHERE category = ? AND stock < ?
// Produits avec stock disponible, excluant certaines catégories
List<Product> findByStockGreaterThanAndCategoryNotIn(
Integer minStock,
List<String> excludedCategories
);
// SQL: WHERE stock > ? AND category NOT IN (?, ?, ?)
}
Exemple 3: Recherche Utilisateurs
public interface UserRepository extends JpaRepository<User, Long> {
// Utilisateurs actifs avec email vérifié
List<User> findByActiveTrueAndEmailVerifiedTrue();
// Utilisateurs créés dans une période
List<User> findByCreatedAtBetween(LocalDate start, LocalDate end);
// Utilisateurs avec nom contenant un mot-clé (insensible à la casse)
List<User> findByNameContainingIgnoreCase(String keyword);
}
Tableau Récapitulatif des 15+ Mots-Clés
| Mot-clé | Syntaxe | SQL | Usage |
|---|---|---|---|
| And | findByNameAndPrice | WHERE name = ? AND price = ? | Combiner conditions |
| Or | findByNameOrCategory | WHERE name = ? OR category = ? | Alternative |
| Between | findByPriceBetween | WHERE price BETWEEN ? AND ? | Intervalle |
| LessThan | findByPriceLessThan | WHERE price < ? | Inférieur |
| LessThanEqual | findByPriceLessThanEqual | WHERE price <= ? | Inférieur ou égal |
| GreaterThan | findByPriceGreaterThan | WHERE price > ? | Supérieur |
| GreaterThanEqual | findByPriceGreaterThanEqual | WHERE price >= ? | Supérieur ou égal |
| Like | findByNameLike | WHERE name LIKE ? | Pattern avec % |
| Containing | findByNameContaining | WHERE name LIKE %?% | Contient |
| StartingWith | findByNameStartingWith | WHERE name LIKE ?% | Commence par |
| EndingWith | findByNameEndingWith | WHERE name LIKE %? | Finit par |
| In | findByCategoryIn | WHERE category IN (?) | Dans liste |
| NotIn | findByCategoryNotIn | WHERE category NOT IN (?) | Pas dans liste |
| IsNull | findByDiscountIsNull | WHERE discount IS NULL | Est null |
| IsNotNull | findByDiscountIsNotNull | WHERE discount IS NOT NULL | N'est pas null |
| True | findByActiveTrue | WHERE active = true | Vrai |
| False | findByActiveFalse | WHERE active = false | Faux |
| IgnoreCase | findByNameIgnoreCase | WHERE UPPER(name) = UPPER(?) | Insensible casse |
| OrderBy | findByOrderByPriceAsc | ORDER BY price ASC | Tri |
Conseils et Bonnes Pratiques
1. Noms de Méthodes Lisibles
✅ BON:
findByPriceBetweenAndCategoryOrderByNameAsc
- Lisible
- Clair
- Suit les conventions
❌ MAUVAIS:
findByPAndC // Trop court
findProductsWherePriceIsBetweenMinAndMaxAndCategoryEqualsGivenCategoryOrderedByName // Trop long
2. Limiter la Complexité
Si la méthode devient trop complexe, utilisez @Query:
// ❌ Trop complexe
findByActiveTrueAndPriceBetweenAndCategoryInAndStockGreaterThanAndNameContainingOrderByPriceAscNameDesc
// ✅ Utilisez @Query à la place
@Query("SELECT p FROM Product p WHERE p.active = true AND ...")
List<Product> findComplexQuery(...);
3. Tester les Méthodes
@Test
public void testFindByPriceBetween() {
// Arrange
productRepo.save(new Product("Cheap", 50.0));
productRepo.save(new Product("Medium", 150.0));
productRepo.save(new Product("Expensive", 500.0));
// Act
List<Product> results = productRepo.findByPriceBetween(100.0, 200.0);
// Assert
assertEquals(1, results.size());
assertEquals("Medium", results.get(0).getName());
}
Résumé du Chapitre
Ce que Vous Avez Appris
✅ 15+ mots-clés pour créer des requêtes
✅ Combinaisons de mots-clés
✅ Recherche textuelle (Like, Containing, etc.)
✅ Comparaisons (LessThan, GreaterThan, Between)
✅ Listes (In, NotIn)
✅ Null (IsNull, IsNotNull)
✅ Booléens (True, False)
✅ Tri (OrderBy)
Maintenant Vous Pouvez
// Créer des requêtes complexes sans SQL!
List<Product> findByActiveTrueAndPriceBetweenAndCategoryInOrderByPriceAsc(
Double min,
Double max,
List<String> categories
);
Auto-Évaluation
Créez mentalement la méthode pour:
- Trouver les produits entre 100€ et 500€
- Trouver les produits contenant "phone" dans le nom
- Trouver les produits actifs avec stock > 10
- Trouver les utilisateurs créés après une date
- Trouver les commandes non payées
Réponses:
findByPriceBetween(Double min, Double max)findByNameContaining(String keyword)findByActiveTrueAndStockGreaterThan(Integer minStock)findByCreatedAtAfter(LocalDate date)findByPaidFalse()
Prochaine Étape
Vous maîtrisez les conventions de nommage! Passez aux Relations entre Entités.