LIKE consultas em repositórios JPA do Spring

LIKE consultas em repositórios JPA do Spring

1. Introdução

Neste tutorial rápido, vamos cobrir várias maneiras de criar consultas LIKE emSpring JPA Repositories.

Começaremos observando as várias palavras-chave que podemos usar ao criar métodos de consulta. Em seguida, cobriremos a anotação@Query com parâmetros nomeados e ordenados.

2. Configuração

Para nosso exemplo, consultaremos uma tabelamovie.

Vamos definir nossa entidadeMovie:

@Entity
public class Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String title;
    private String director;
    private String rating;
    private int duration;

    // standard getters and setters
}

Com nossa entidadeMovie definida, vamos criar alguns exemplos de instruções de inserção:

INSERT INTO movie(id, title, director, rating, duration)
    VALUES(1, 'Godzilla: King of the Monsters', ' Michael Dougherty', 'PG-13', 132);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(2, 'Avengers: Endgame', 'Anthony Russo', 'PG-13', 181);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(3, 'Captain Marvel', 'Anna Boden', 'PG-13', 123);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(4, 'Dumbo', 'Tim Burton', 'PG', 112);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(5, 'Booksmart', 'Olivia Wilde', 'R', 102);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(6, 'Aladdin', 'Guy Ritchie', 'PG', 128);
INSERT INTO movie(id, title, director, rating, duration)
    VALUES(7, 'The Sun Is Also a Star', 'Ry Russo-Young', 'PG-13', 100);

3. Métodos de consulta LIKE

Para muitos cenários de consulta LIKE simples, podemos tirar proveito de uma variedade de palavras-chave para criar métodos de consulta em nossos repositórios.

Vamos explorá-los agora.

3.1. Containing,Contains,IsContaining eLike

Vejamos como podemos realizar a seguinte consulta LIKE com um método de consulta:

SELECT * FROM movie WHERE title LIKE '%in%';

Primeiro, vamos definir os métodos de consulta usandoContaining,Contains,eIsContaining:

List findByTitleContaining(String title);
List findByTitleContains(String title);
List findByTitleIsContaining(String title);

Vamos chamar nossos métodos de consulta com o título parcialin:

List results = movieRepository.findByTitleContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleIsContaining("in");
assertEquals(3, results.size());

results = movieRepository.findByTitleContains("in");
assertEquals(3, results.size());

Podemos esperar que cada um dos três métodos retorne os mesmos resultados.

O Spring também nos fornece uma palavra-chaveLike, mas se comporta de maneira um pouco diferente, pois somos obrigados a fornecer o caractere curinga com nosso parâmetro de pesquisa.

Vamos definir um método de consulta LIKE:

List findByTitleLike(String title);

Agora, vamos chamar nosso métodofindByTitleLike com o mesmo valor que usamos antes, mas incluindo os caracteres curinga:

results = movieRepository.findByTitleLike("%in%");
assertEquals(3, results.size());

3.2. StartsWith

Agora, vamos examinar a seguinte consulta:

SELECT * FROM Movie WHERE Rating LIKE 'PG%';

Vamos usar a palavra-chaveStartsWith para criar um método de consulta:

List findByRatingStartsWith(String rating);

Com nosso método definido, vamos chamá-lo com o valorPG:

List results = movieRepository.findByRatingStartsWith("PG");
assertEquals(6, results.size());

3.3. EndsWith

O Spring nos fornece a funcionalidade oposta com a palavra-chaveEndsWith.

Vamos considerar esta consulta:

SELECT * FROM Movie WHERE director LIKE '%Burton';

Agora, vamos definir um método de consultaEndsWith:

List findByDirectorEndsWith(String director);

Depois de definir nosso método, vamos chamá-lo com o parâmetroBurton:

List results = movieRepository.findByDirectorEndsWith("Burton");
assertEquals(1, results.size());

3.4. Insensibilidade ao caso

Muitas vezes queremos encontrar todos os registros que contenham uma determinada string, independentemente do caso. Em SQL, podemos fazer isso forçando a coluna a usar todas as letras maiúsculas ou minúsculas e fornecer os mesmos valores que estamos consultando.

Com Spring JPA, podemos usar a palavra-chaveIgnoreCase combinada com uma de nossas outras palavras-chave:

List findByTitleContainingIgnoreCase(String title);

Agora podemos chamar o método comthee esperar obter resultados contendo ambos, resultados em maiúsculas e minúsculas:

List results = movieRepository.findByTitleContainingIgnoreCase("the");
assertEquals(2, results.size());

3.5. Not

Às vezes, queremos encontrar todos os registros que não contêm uma string específica. We can use the NotContains, NotContaining, and NotLike keywords to do that.

Vamos definir uma consulta usandoNotContaining para encontrar filmes com classificações que não contêmPG:

List findByRatingNotContaining(String rating);

Agora, vamos chamar nosso método recém-definido:

List results = movieRepository.findByRatingNotContaining("PG");
assertEquals(1, results.size());

Para obter a funcionalidade que encontra registros onde o diretor não começa com uma string específica, vamos usar a palavra-chaveNotLike para manter o controle sobre a colocação do curinga:

List findByDirectorNotLike(String director);

Por fim, vamos chamar o método para encontrar todos os filmes onde o nome do diretor começa com algo diferente deAn:

List results = movieRepository.findByDirectorNotLike("An%");
assertEquals(5, results.size());

Podemos usarNotLike de maneira semelhante para realizar umNot combinado com o tipo de funcionalidadeEndsWith.

4. Usando@Query

Às vezes, precisamos criar consultas muito complicadas para os métodos de consulta ou que resultem em nomes de métodos absurdamente longos. Nesses casos,we can use the @Query annotation to query our database.

4.1. Parâmetros nomeados

Para fins de comparação, vamos criar uma consulta que é equivalente ao métodofindByTitleContaining que definimos anteriormente:

@Query("SELECT m FROM Movie m WHERE m.title LIKE %:title%")
List searchByTitleLike(@Param("title") String title);

Incluímos nossos curingas na consulta que fornecemos. A anotação@Param é importante aqui porque estamos usando um parâmetro nomeado.

4.2. Parâmetros ordenados

Além dos parâmetros nomeados, podemos usar parâmetros ordenados em nossas consultas:

@Query("SELECT m FROM Movie m WHERE m.rating LIKE ?1%")
List searchByRatingStartsWith(String rating);

Temos o controle de nossos curingas, então esta consulta é equivalente ao método de consultafindByRatingStartsWith.

Vamos encontrar todos os filmes com uma classificação começando comPG:

List results = movieRepository.searchByRatingStartsWith("PG");
assertEquals(6, results.size());

Quando usamos parâmetros ordenados em consultas LIKE com dados não confiáveis, devemos escapar dos valores de pesquisa recebidos.

Se estivermos usando Spring Boot 2.4.1 ou posterior, podemos usar o métodoSpELescape:

@Query("SELECT m FROM Movie m WHERE m.director LIKE %?#{escape([0])} escape ?#{escapeCharacter()}")
List searchByDirectorEndsWith(String director);

Agora, vamos chamar nosso método com o valorBurton:

List results = movieRepository.searchByDirectorEndsWith("Burton");
assertEquals(1, results.size());

5. Conclusão

Neste breve tutorial, aprendemos como criar consultas LIKE nos repositórios Spring JPA.

Primeiro, aprendemos a usar as palavras-chave fornecidas para criar métodos de consulta. Em seguida, aprendemos como realizar as mesmas tarefas usando o parâmetro@Query com parâmetros nomeados e ordenados.

O código de exemplo completo está disponívelover on GitHub.