Pular para o conteúdo principal

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​

  1. As 15+ palavras-chave do Spring Data JPA
  2. Como combiná-las
  3. 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:


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-chaveSintaxeSQLUso
AndfindByNameAndPriceWHERE name = ? AND price = ?Combinar condições
OrfindByNameOrCategoryWHERE name = ? OR category = ?Alternativa
BetweenfindByPriceBetweenWHERE price BETWEEN ? AND ?Intervalo
LessThanfindByPriceLessThanWHERE price < ?Menor que
LessThanEqualfindByPriceLessThanEqualWHERE price <= ?Menor ou igual
GreaterThanfindByPriceGreaterThanWHERE price > ?Maior que
GreaterThanEqualfindByPriceGreaterThanEqualWHERE price >= ?Maior ou igual
LikefindByNameLikeWHERE name LIKE ?Padrão com %
ContainingfindByNameContainingWHERE name LIKE %?%Contém
StartingWithfindByNameStartingWithWHERE name LIKE ?%Começa com
EndingWithfindByNameEndingWithWHERE name LIKE %?Termina com
InfindByCategoryInWHERE category IN (?)Em lista
NotInfindByCategoryNotInWHERE category NOT IN (?)Não está na lista
IsNullfindByDiscountIsNullWHERE discount IS NULLÉ null
IsNotNullfindByDiscountIsNotNullWHERE discount IS NOT NULLNão é null
TruefindByActiveTrueWHERE active = trueVerdadeiro
FalsefindByActiveFalseWHERE active = falseFalso
IgnoreCasefindByNameIgnoreCaseWHERE UPPER(name) = UPPER(?)Case-insensitive
OrderByfindByOrderByPriceAscORDER BY price ASCOrdenaçã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:

  1. Encontrar produtos entre 100€ e 500€
  2. Encontrar produtos contendo "phone" no nome
  3. Encontrar produtos ativos com estoque > 10
  4. Encontrar usuários criados após uma data
  5. Encontrar pedidos não pagos

Respostas:

  1. findByPriceBetween(Double min, Double max)
  2. findByNameContaining(String keyword)
  3. findByActiveTrueAndStockGreaterThan(Integer minStock)
  4. findByCreatedAtAfter(LocalDate date)
  5. findByPaidFalse()

Próximo Passo​

Você domina as convenções de nomeação! Avance para Relações entre Entidades.

➡️ Capítulo 2: Relações entre Entidades

⬅️ Voltar ao Módulo 6