Capítulo 1: Convenciones de Nombres Avanzadas
Introducción
En el Módulo 2, aprendió 3 palabras clave simples: findBy, And, Or.
¡Ahora aprenderá más de 15 palabras clave adicionales para crear consultas complejas!
Lo que va a aprender
- Las 15+ palabras clave de Spring Data JPA
- Cómo combinarlas
- Ejemplos para cada palabra clave
Duración: 1h
¿Cómo Funciona?
Principio Mágico de Spring Data JPA
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByPriceLessThan(Double maxPrice);
// ^^^^^^ ^^^^^ ^^^^^^^
// find By PriceLessThan
}
¡Spring lee el nombre del método y genera el SQL automáticamente!
-- SQL generado automáticamente:
SELECT * FROM product WHERE price < ?
¡Usted NO escribe SQL, Spring lo hace por usted!
Estructura de los Nombres de Métodos
findBy + [Campo] + [Operación] + [OtroCampo] + [Operación]
Ejemplos:
findByName // WHERE name = ?
findByPriceLessThan // WHERE price < ?
findByNameAndPrice // WHERE name = ? AND price = ?
findByPriceBetween // WHERE price BETWEEN ? AND ?
Las 15+ Palabras Clave
1. And / Or (Ya las conoce)
Combinar varias condiciones:
// 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 = ?
Ejemplo concreto:
// Encontrar un producto "Laptop" a 999.99€
productRepo.findByNameAndPrice("Laptop", 999.99);
2. Between (Entre dos valores)
Encontrar valores en un intervalo:
List<Product> findByPriceBetween(Double min, Double max);
// SQL: WHERE price BETWEEN ? AND ?
Ejemplo:
// Productos entre 100€ y 500€
List<Product> products = productRepo.findByPriceBetween(100.0, 500.0);
Casos de uso:
- Precio en un rango
- Fechas entre dos momentos
- Edades entre mínimo y máximo
3. LessThan / GreaterThan (Comparaciones)
Comparar valores numéricos o fechas:
// Menor que
List<Product> findByPriceLessThan(Double maxPrice);
// SQL: WHERE price < ?
// Menor o igual
List<Product> findByPriceLessThanEqual(Double maxPrice);
// SQL: WHERE price <= ?
// Mayor que
List<Product> findByPriceGreaterThan(Double minPrice);
// SQL: WHERE price > ?
// Mayor o igual
List<Product> findByPriceGreaterThanEqual(Double minPrice);
// SQL: WHERE price >= ?
Ejemplos:
// Productos a menos de 100€
productRepo.findByPriceLessThan(100.0);
// Productos a 100€ o menos
productRepo.findByPriceLessThanEqual(100.0);
// Productos a más de 1000€
productRepo.findByPriceGreaterThan(1000.0);
Casos de uso:
- Precio mínimo/máximo
- Stock mínimo
- Edad mínima/máxima
- Fechas antes/después
4. Like / Containing / StartingWith / EndingWith (Búsqueda de Texto)
Buscar en cadenas de texto:
// LIKE (usted proporciona los %)
List<Product> findByNameLike(String pattern);
// SQL: WHERE name LIKE ?
// Uso: findByNameLike("%Laptop%")
// CONTAINING (Spring agrega los % automáticamente)
List<Product> findByNameContaining(String keyword);
// SQL: WHERE name LIKE ?
// Uso: findByNameContaining("Laptop")
// Busca: %Laptop%
// STARTING WITH (busca al inicio)
List<Product> findByNameStartingWith(String prefix);
// SQL: WHERE name LIKE ?
// Uso: findByNameStartingWith("Mac")
// Busca: Mac%
// ENDING WITH (busca al final)
List<Product> findByNameEndingWith(String suffix);
// SQL: WHERE name LIKE ?
// Uso: findByNameEndingWith("Pro")
// Busca: %Pro
Ejemplos:
// Productos que contienen "phone" (iPhone, smartphone, etc.)
productRepo.findByNameContaining("phone");
// Productos que comienzan con "Mac" (MacBook, Mac Mini, etc.)
productRepo.findByNameStartingWith("Mac");
// Productos que terminan con "Pro" (MacBook Pro, iPad Pro, etc.)
productRepo.findByNameEndingWith("Pro");
Diferencia Like vs Containing:
// Like - usted controla los %
findByNameLike("%Laptop%") // Contiene Laptop
findByNameLike("Laptop%") // Comienza con Laptop
findByNameLike("%Laptop") // Termina con Laptop
// Containing - Spring agrega los %
findByNameContaining("Laptop") // Contiene Laptop (%Laptop%)
5. In / NotIn (En una lista)
Verificar si un valor está en una lista:
// IN
List<Product> findByCategoryIn(List<String> categories);
// SQL: WHERE category IN (?, ?, ?)
// NOT IN
List<Product> findByCategoryNotIn(List<String> categories);
// SQL: WHERE category NOT IN (?, ?, ?)
Ejemplos:
// Productos en varias categorías
List<String> categories = Arrays.asList("Electronics", "Computers", "Phones");
productRepo.findByCategoryIn(categories);
// Productos NO en estas categorías
productRepo.findByCategoryNotIn(categories);
Casos de uso:
- Filtrar por varias categorías
- Excluir ciertos estados
- Buscar por varios IDs
6. IsNull / IsNotNull (Valores nulos)
Verificar si un campo es null:
// IS NULL
List<Product> findByDiscountIsNull();
// SQL: WHERE discount IS NULL
// IS NOT NULL (o NotNull)
List<Product> findByDiscountIsNotNull();
List<Product> findByDiscountNotNull();
// SQL: WHERE discount IS NOT NULL
Ejemplos:
// Productos sin descuento
productRepo.findByDiscountIsNull();
// Productos con descuento
productRepo.findByDiscountIsNotNull();
Casos de uso:
- Productos sin imagen
- Pedidos sin fecha de entrega
- Usuarios sin email
7. True / False (Booleanos)
Verificar valores booleanos:
// TRUE
List<Product> findByActiveTrue();
// SQL: WHERE active = true
// FALSE
List<Product> findByActiveFalse();
// SQL: WHERE active = false
Ejemplos:
// Productos activos
productRepo.findByActiveTrue();
// Productos inactivos
productRepo.findByActiveFalse();
Casos de uso:
- Productos activos/inactivos
- Usuarios verificados/no verificados
- Pedidos pagados/no pagados
8. IgnoreCase (Ignorar mayúsculas/minúsculas)
Búsqueda insensible a mayúsculas/minúsculas:
// Un solo campo
List<Product> findByNameIgnoreCase(String name);
// SQL: WHERE UPPER(name) = UPPER(?)
// Varios campos
List<Product> findByNameAndCategoryAllIgnoreCase(String name, String category);
// SQL: WHERE UPPER(name) = UPPER(?) AND UPPER(category) = UPPER(?)
Ejemplos:
// Encuentra "laptop", "LAPTOP", "Laptop", etc.
productRepo.findByNameIgnoreCase("laptop");
Casos de uso:
- Búsqueda de usuario (insensible a mayúsculas/minúsculas)
- Búsqueda de producto
- Email (john@email.com = JOHN@email.com)
9. OrderBy (Ordenar)
Ordenar los resultados:
// Orden ascendente
List<Product> findByCategoryOrderByPriceAsc(String category);
// SQL: WHERE category = ? ORDER BY price ASC
// Orden descendente
List<Product> findByCategoryOrderByPriceDesc(String category);
// SQL: WHERE category = ? ORDER BY price DESC
// Orden múltiple
List<Product> findByCategoryOrderByPriceAscNameDesc(String category);
// SQL: WHERE category = ? ORDER BY price ASC, name DESC
Ejemplos:
// Laptops del más barato al más caro
productRepo.findByCategoryOrderByPriceAsc("Laptops");
// Laptops del más caro al más barato
productRepo.findByCategoryOrderByPriceDesc("Laptops");
Combinaciones Potentes
Ejemplo 1: Búsqueda Compleja E-commerce
public interface ProductRepository extends JpaRepository<Product, Long> {
// Productos activos, en un rango de precios, ordenados por nombre
List<Product> findByActiveTrueAndPriceBetweenOrderByNameAsc(
Double minPrice,
Double maxPrice
);
// SQL: WHERE active = true
// AND price BETWEEN ? AND ?
// ORDER BY name ASC
}
Uso:
// Productos activos entre 100€ y 500€, ordenados por nombre
productRepo.findByActiveTrueAndPriceBetweenOrderByNameAsc(100.0, 500.0);
Ejemplo 2: Gestión de Inventario
public interface ProductRepository extends JpaRepository<Product, Long> {
// Productos agotados en una categoría
List<Product> findByCategoryAndStockLessThan(String category, Integer minStock);
// SQL: WHERE category = ? AND stock < ?
// Productos con stock disponible, excluyendo ciertas categorías
List<Product> findByStockGreaterThanAndCategoryNotIn(
Integer minStock,
List<String> excludedCategories
);
// SQL: WHERE stock > ? AND category NOT IN (?, ?, ?)
}
Ejemplo 3: Búsqueda de Usuarios
public interface UserRepository extends JpaRepository<User, Long> {
// Usuarios activos con email verificado
List<User> findByActiveTrueAndEmailVerifiedTrue();
// Usuarios creados en un periodo
List<User> findByCreatedAtBetween(LocalDate start, LocalDate end);
// Usuarios con nombre que contiene una palabra clave (insensible a mayúsculas/minúsculas)
List<User> findByNameContainingIgnoreCase(String keyword);
}
Tabla Resumen de las 15+ Palabras Clave
| Palabra clave | Sintaxis | SQL | Uso |
|---|---|---|---|
| And | findByNameAndPrice | WHERE name = ? AND price = ? | Combinar condiciones |
| Or | findByNameOrCategory | WHERE name = ? OR category = ? | Alternativa |
| Between | findByPriceBetween | WHERE price BETWEEN ? AND ? | Intervalo |
| LessThan | findByPriceLessThan | WHERE price < ? | Menor |
| LessThanEqual | findByPriceLessThanEqual | WHERE price <= ? | Menor o igual |
| GreaterThan | findByPriceGreaterThan | WHERE price > ? | Mayor |
| GreaterThanEqual | findByPriceGreaterThanEqual | WHERE price >= ? | Mayor o igual |
| Like | findByNameLike | WHERE name LIKE ? | Patrón con % |
| Containing | findByNameContaining | WHERE name LIKE %?% | Contiene |
| StartingWith | findByNameStartingWith | WHERE name LIKE ?% | Comienza con |
| EndingWith | findByNameEndingWith | WHERE name LIKE %? | Termina con |
| In | findByCategoryIn | WHERE category IN (?) | En lista |
| NotIn | findByCategoryNotIn | WHERE category NOT IN (?) | No en lista |
| IsNull | findByDiscountIsNull | WHERE discount IS NULL | Es null |
| IsNotNull | findByDiscountIsNotNull | WHERE discount IS NOT NULL | No es null |
| True | findByActiveTrue | WHERE active = true | Verdadero |
| False | findByActiveFalse | WHERE active = false | Falso |
| IgnoreCase | findByNameIgnoreCase | WHERE UPPER(name) = UPPER(?) | Insensible a mayúsculas/minúsculas |
| OrderBy | findByOrderByPriceAsc | ORDER BY price ASC | Ordenar |
Consejos y Buenas Prácticas
1. Nombres de Métodos Legibles
✅ BUENO:
findByPriceBetweenAndCategoryOrderByNameAsc
- Legible
- Claro
- Sigue las convenciones
❌ MALO:
findByPAndC // Demasiado corto
findProductsWherePriceIsBetweenMinAndMaxAndCategoryEqualsGivenCategoryOrderedByName // Demasiado largo
2. Limitar la Complejidad
Si el método se vuelve demasiado complejo, utilice @Query:
// ❌ Demasiado complejo
findByActiveTrueAndPriceBetweenAndCategoryInAndStockGreaterThanAndNameContainingOrderByPriceAscNameDesc
// ✅ Utilice @Query en su lugar
@Query("SELECT p FROM Product p WHERE p.active = true AND ...")
List<Product> findComplexQuery(...);
3. Probar los Métodos
@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());
}
Resumen del Capítulo
Lo que Ha Aprendido
✅ 15+ palabras clave para crear consultas
✅ Combinaciones de palabras clave
✅ Búsqueda de texto (Like, Containing, etc.)
✅ Comparaciones (LessThan, GreaterThan, Between)
✅ Listas (In, NotIn)
✅ Null (IsNull, IsNotNull)
✅ Booleanos (True, False)
✅ Ordenar (OrderBy)
Ahora Puede
// ¡Crear consultas complejas sin SQL!
List<Product> findByActiveTrueAndPriceBetweenAndCategoryInOrderByPriceAsc(
Double min,
Double max,
List<String> categories
);
Autoevaluación
Mentalmente cree el método para:
- Encontrar los productos entre 100€ y 500€
- Encontrar los productos que contienen "phone" en el nombre
- Encontrar los productos activos con stock > 10
- Encontrar los usuarios creados después de una fecha
- Encontrar los pedidos no pagados
Respuestas:
findByPriceBetween(Double min, Double max)findByNameContaining(String keyword)findByActiveTrueAndStockGreaterThan(Integer minStock)findByCreatedAtAfter(LocalDate date)findByPaidFalse()
Próximo Paso
¡Usted domina las convenciones de nombres! Continúe con las Relaciones entre Entidades.