Capítulo 1: Convenções de Nomeação Avançadas
Introdução
No Módulo 2, você aprendeu 3 palavras-chave simples: findBy, And, Or.
Agora, você vai aprender mais de 15 palavras-chave para criar consultas complexas!
O que você vai aprender
- As 15+ palavras-chave do Spring Data JPA
- Como combiná-las
- Exemplos para cada palavra-chave
Duração: 1h
Como Funciona?
Princípio Mágico do Spring Data JPA
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByPriceLessThan(Double maxPrice);
// ^^^^^^ ^^^^^ ^^^^^^^
// find By PriceLessThan
}
O Spring lê o nome do método e gera o SQL automaticamente!
-- SQL gerado automaticamente:
SELECT * FROM product WHERE price < ?
Você NÃO escreve SQL, o Spring faz isso para você!
Estrutura dos Nomes de Métodos
findBy + [Campo] + [Operação] + [OutroCampo] + [Operação]
Exemplos:
findByName // WHERE name = ?
findByPriceLessThan // WHERE price < ?
findByNameAndPrice // WHERE name = ? AND price = ?
findByPriceBetween // WHERE price BETWEEN ? AND ?
As 15+ Palavras-Chave
1. And / Or (Você já conhece)
Combinar várias condições:
// 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 = ?
Exemplo prático:
// Encontrar um produto "Laptop" por 999.99€
productRepo.findByNameAndPrice("Laptop", 999.99);
2. Between (Entre dois valores)
Encontrar valores dentro de um intervalo:
List<Product> findByPriceBetween(Double min, Double max);
// SQL: WHERE price BETWEEN ? AND ?
Exemplo:
// Produtos entre 100€ e 500€
List<Product> products = productRepo.findByPriceBetween(100.0, 500.0);
Casos de uso:
- Preço em uma faixa
- Datas entre dois momentos
- Idades entre mínimo e máximo
3. LessThan / GreaterThan (Comparações)
Comparar valores numéricos ou datas:
// Menor que
List<Product> findByPriceLessThan(Double maxPrice);
// SQL: WHERE price < ?
// Menor ou igual
List<Product> findByPriceLessThanEqual(Double maxPrice);
// SQL: WHERE price <= ?
// Maior que
List<Product> findByPriceGreaterThan(Double minPrice);
// SQL: WHERE price > ?
// Maior ou igual
List<Product> findByPriceGreaterThanEqual(Double minPrice);
// SQL: WHERE price >= ?
Exemplos:
// Produtos com preço menor que 100€
productRepo.findByPriceLessThan(100.0);
// Produtos com preço até 100€
productRepo.findByPriceLessThanEqual(100.0);
// Produtos com preço maior que 1000€
productRepo.findByPriceGreaterThan(1000.0);
Casos de uso:
- Preço mínimo/máximo
- Estoque mínimo
- Idade mínima/máxima
- Datas antes/depois
4. Like / Containing / StartingWith / EndingWith (Busca por Texto)
Buscar em strings de texto:
// LIKE (você fornece os %)
List<Product> findByNameLike(String pattern);
// SQL: WHERE name LIKE ?
// Uso: findByNameLike("%Laptop%")
// CONTAINING (Spring adiciona os % automaticamente)
List<Product> findByNameContaining(String keyword);
// SQL: WHERE name LIKE ?
// Uso: findByNameContaining("Laptop")
// Busca: %Laptop%
// STARTING WITH (busca no início)
List<Product> findByNameStartingWith(String prefix);
// SQL: WHERE name LIKE ?
// Uso: findByNameStartingWith("Mac")
// Busca: Mac%
// ENDING WITH (busca no final)
List<Product> findByNameEndingWith(String suffix);
// SQL: WHERE name LIKE ?
// Uso: findByNameEndingWith("Pro")
// Busca: %Pro
Exemplos:
// Produtos contendo "phone" (iPhone, smartphone, etc.)
productRepo.findByNameContaining("phone");
// Produtos começando com "Mac" (MacBook, Mac Mini, etc.)
productRepo.findByNameStartingWith("Mac");
// Produtos terminando com "Pro" (MacBook Pro, iPad Pro, etc.)
productRepo.findByNameEndingWith("Pro");
Diferença Like vs Containing:
// Like - você controla os %
findByNameLike("%Laptop%") // Contém Laptop
findByNameLike("Laptop%") // Começa com Laptop
findByNameLike("%Laptop") // Termina com Laptop
// Containing - Spring adiciona os %
findByNameContaining("Laptop") // Contém Laptop (%Laptop%)
5. In / NotIn (Em uma lista)
Verificar se um valor está em uma 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 (?, ?, ?)
Exemplos:
// Produtos em várias categorias
List<String> categories = Arrays.asList("Electronics", "Computers", "Phones");
productRepo.findByCategoryIn(categories);
// Produtos NÃO nessas categorias
productRepo.findByCategoryNotIn(categories);
Casos de uso:
- Filtrar por várias categorias
- Excluir certos status
- Buscar por vários IDs
6. IsNull / IsNotNull (Valores nulos)
Verificar se um campo é 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
Exemplos:
// Produtos sem desconto
productRepo.findByDiscountIsNull();
// Produtos com desconto
productRepo.findByDiscountIsNotNull();
Casos de uso:
- Produtos sem imagem
- Pedidos sem data de entrega
- Usuários sem email
7. True / False (Booleanos)
Verificar valores booleanos:
// TRUE
List<Product> findByActiveTrue();
// SQL: WHERE active = true
// FALSE
List<Product> findByActiveFalse();
// SQL: WHERE active = false
Exemplos:
// Produtos ativos
productRepo.findByActiveTrue();
// Produtos inativos
productRepo.findByActiveFalse();
Casos de uso:
- Produtos ativos/inativos
- Usuários verificados/não verificados
- Pedidos pagos/não pagos
8. IgnoreCase (Ignorar maiúsculas/minúsculas)
Busca sem diferenciar maiúsculas/minúsculas:
// Um campo
List<Product> findByNameIgnoreCase(String name);
// SQL: WHERE UPPER(name) = UPPER(?)
// Vários campos
List<Product> findByNameAndCategoryAllIgnoreCase(String name, String category);
// SQL: WHERE UPPER(name) = UPPER(?) AND UPPER(category) = UPPER(?)
Exemplos:
// Encontra "laptop", "LAPTOP", "Laptop", etc.
productRepo.findByNameIgnoreCase("laptop");
Casos de uso:
- Busca de usuário (case-insensitive)
- Busca de produto
- Email (john@email.com = JOHN@email.com)
9. OrderBy (Ordenação)
Ordenar os resultados:
// Ordem crescente
List<Product> findByCategoryOrderByPriceAsc(String category);
// SQL: WHERE category = ? ORDER BY price ASC
// Ordem decrescente
List<Product> findByCategoryOrderByPriceDesc(String category);
// SQL: WHERE category = ? ORDER BY price DESC
// Ordenação múltipla
List<Product> findByCategoryOrderByPriceAscNameDesc(String category);
// SQL: WHERE category = ? ORDER BY price ASC, name DESC
Exemplos:
// Laptops do mais barato ao mais caro
productRepo.findByCategoryOrderByPriceAsc("Laptops");
// Laptops do mais caro ao mais barato
productRepo.findByCategoryOrderByPriceDesc("Laptops");
Combinações Poderosas
Exemplo 1: Busca Complexa E-commerce
public interface ProductRepository extends JpaRepository<Product, Long> {
// Produtos ativos, em uma faixa de preço, ordenados por nome
List<Product> findByActiveTrueAndPriceBetweenOrderByNameAsc(
Double minPrice,
Double maxPrice
);
// SQL: WHERE active = true
// AND price BETWEEN ? AND ?
// ORDER BY name ASC
}
Uso:
// Produtos ativos entre 100€ e 500€, ordenados por nome
productRepo.findByActiveTrueAndPriceBetweenOrderByNameAsc(100.0, 500.0);
Exemplo 2: Gestão de Estoque
public interface ProductRepository extends JpaRepository<Product, Long> {
// Produtos fora de estoque em uma categoria
List<Product> findByCategoryAndStockLessThan(String category, Integer minStock);
// SQL: WHERE category = ? AND stock < ?
// Produtos com estoque disponível, excluindo certas categorias
List<Product> findByStockGreaterThanAndCategoryNotIn(
Integer minStock,
List<String> excludedCategories
);
// SQL: WHERE stock > ? AND category NOT IN (?, ?, ?)
}
Exemplo 3: Busca de Usuários
public interface UserRepository extends JpaRepository<User, Long> {
// Usuários ativos com email verificado
List<User> findByActiveTrueAndEmailVerifiedTrue();
// Usuários criados em um período
List<User> findByCreatedAtBetween(LocalDate start, LocalDate end);
// Usuários com nome contendo uma palavra-chave (case-insensitive)
List<User> findByNameContainingIgnoreCase(String keyword);
}
Tabela Resumo das 15+ Palavras-Chave
| Palavra-chave | Sintaxe | SQL | Uso |
|---|---|---|---|
| And | findByNameAndPrice | WHERE name = ? AND price = ? | Combinar condições |
| Or | findByNameOrCategory | WHERE name = ? OR category = ? | Alternativa |
| Between | findByPriceBetween | WHERE price BETWEEN ? AND ? | Intervalo |
| LessThan | findByPriceLessThan | WHERE price < ? | Menor que |
| LessThanEqual | findByPriceLessThanEqual | WHERE price <= ? | Menor ou igual |
| GreaterThan | findByPriceGreaterThan | WHERE price > ? | Maior que |
| GreaterThanEqual | findByPriceGreaterThanEqual | WHERE price >= ? | Maior ou igual |
| Like | findByNameLike | WHERE name LIKE ? | Padrão com % |
| Containing | findByNameContaining | WHERE name LIKE %?% | Contém |
| StartingWith | findByNameStartingWith | WHERE name LIKE ?% | Começa com |
| EndingWith | findByNameEndingWith | WHERE name LIKE %? | Termina com |
| In | findByCategoryIn | WHERE category IN (?) | Em lista |
| NotIn | findByCategoryNotIn | WHERE category NOT IN (?) | Não está na lista |
| IsNull | findByDiscountIsNull | WHERE discount IS NULL | É null |
| IsNotNull | findByDiscountIsNotNull | WHERE discount IS NOT NULL | Não é null |
| True | findByActiveTrue | WHERE active = true | Verdadeiro |
| False | findByActiveFalse | WHERE active = false | Falso |
| IgnoreCase | findByNameIgnoreCase | WHERE UPPER(name) = UPPER(?) | Case-insensitive |
| OrderBy | findByOrderByPriceAsc | ORDER BY price ASC | Ordenação |
Dicas e Boas Práticas
1. Nomes de Métodos Legíveis
✅ BOM:
findByPriceBetweenAndCategoryOrderByNameAsc
- Legível
- Claro
- Segue as convenções
❌ RUIM:
findByPAndC // Muito curto
findProductsWherePriceIsBetweenMinAndMaxAndCategoryEqualsGivenCategoryOrderedByName // Muito longo
2. Limite a Complexidade
Se o método ficar muito complexo, use @Query:
// ❌ Muito complexo
findByActiveTrueAndPriceBetweenAndCategoryInAndStockGreaterThanAndNameContainingOrderByPriceAscNameDesc
// ✅ Use @Query no lugar
@Query("SELECT p FROM Product p WHERE p.active = true AND ...")
List<Product> findComplexQuery(...);
3. Teste os 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());
}
Resumo do Capítulo
O que Você Aprendeu
✅ 15+ palavras-chave para criar consultas
✅ Combinações de palavras-chave
✅ Busca textual (Like, Containing, etc.)
✅ Comparações (LessThan, GreaterThan, Between)
✅ Listas (In, NotIn)
✅ Null (IsNull, IsNotNull)
✅ Booleanos (True, False)
✅ Ordenação (OrderBy)
Agora Você Pode
// Criar consultas complexas sem SQL!
List<Product> findByActiveTrueAndPriceBetweenAndCategoryInOrderByPriceAsc(
Double min,
Double max,
List<String> categories
);
Autoavaliação
Crie mentalmente o método para:
- Encontrar produtos entre 100€ e 500€
- Encontrar produtos contendo "phone" no nome
- Encontrar produtos ativos com estoque > 10
- Encontrar usuários criados após uma data
- Encontrar pedidos não pagos
Respostas:
findByPriceBetween(Double min, Double max)findByNameContaining(String keyword)findByActiveTrueAndStockGreaterThan(Integer minStock)findByCreatedAtAfter(LocalDate date)findByPaidFalse()
Próximo Passo
Você domina as convenções de nomeação! Avance para Relações entre Entidades.