Todos que usaram o Spring Data enfrentaram uma situação em que você tem um repositório para trabalhar com uma entidade e deseja escrever um método universal de busca para pesquisar por um conjunto de parâmetros que o usuário pode definir ou ignorar no formulário de pesquisa. A implementação básica dos métodos find no Spring Data localiza entidades apenas levando em consideração todos os parâmetros, não permitindo a pesquisa por um conjunto limitado. Encontrei uma maneira de resolver esse problema e criei uma biblioteca OpenSource para uso rápido em outros projetos.
Para entender os problemas, vamos imaginar que estamos criando um aplicativo de notebook simples, no qual definimos uma entidade - Pessoa com os campos id, firstName, lastName, phoneNumber.
Person.java@Entity @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(of = "id") public class Person { @Id private Long id; private String firstName; private String lastName; private String phoneNumber; }
Suponha que devemos fornecer uma pesquisa por nome, sobrenome e parte do número de telefone ou por qualquer combinação desses parâmetros e que o método de pesquisa não leve em consideração parâmetros cujos valores são nulos. Para resolver esse problema, você pode seguir de várias maneiras:
- Trabalhe diretamente com o banco de dados através do SQL, crie um método no serviço que gerará dinamicamente a consulta SQL. Algo como
Consulta dinâmica Iterable<Person> find(String firstName, String lastName, String phoneNumber) { List<String> where = new ArrayList(); List params = new ArrayList(); if(firstName != null) { params.add(firstName); where.add("first_name = ?"); } if(lastName != null) { params.add(lastName); where.add("last_name = ?"); } if(phoneNumber != null) { params.add(phoneNumber); where.add("phone_number = ?"); } String sql = "SELECT * FROM person " + (where.isEmpty() ? "" : " WHERE " + String.join(" AND ", where));
- Use a anotação de consulta para um método de pesquisa com verificação de parâmetro como nulo.
@Query @Query("SELECT p FROM Person p " + "WHERE " + "(firstName = :firstName or :firstName is null) and " + "(lastName = :lastName or :lastName is null) and " + "(phoneNumber = :phoneNumber or :phoneNumber is null)" ) Iterable<Person> find( @Param("firstName") String firstName, @Param("lastName") String lastName, @Param("phoneNumber") String phoneNumber );
- Crie métodos de pesquisa para todas as combinações possíveis de parâmetros e chame o método desejado após verificar se os parâmetros são nulos.
Muitos métodos de localização @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> {
Não analisarei as vantagens e desvantagens de cada método, elas são óbvias. Permitam-me apenas dizer que escolhi a terceira opção com a adição de métodos de pesquisa para cada variante da combinação de parâmetros e criei uma biblioteca OpenSource que usa o mecanismo Annotation Processor e, no estágio de compilação, faz todo o trabalho para você. Para usá-lo, você deve conectar a biblioteca (consulte a versão mais recente em
https://github.com/ukman/kolobok ou
https://mvnrepository.com/artifact/com.github.ukman/kolobok ).
<dependency> <groupId>com.github.ukman</groupId> <artifactId>kolobok</artifactId> <version>0.1.2</version> <scope>compile</scope> </dependency>
Então você precisa marcar o método, que deve funcionar de uma nova maneira com a anotação @FindWithOptionalParams.
@Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { @FindWithOptionalParams Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); }
A própria biblioteca irá gerar todos os métodos de pesquisa e a implementação padrão, verificando os parâmetros para null e chamando o método necessário.
PS: escreva nos comentários o que outras anotações podem simplificar seu trabalho com o Spring, talvez eu as adicione também.