Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Busca com muitos parâmetros

Existem situações em que é necessário desenvolver uma tela de busca geral composta por dezenas de campos em que normalmente o usuário utiliza apenas de um a três deles.

Nesse caso, atualmente, qual a recomendação para realizar as consultas ao banco de dados de modo que não precise cadastrar um método para cada possibilidade de busca?

2 respostas
solução!

E aí, Manoel! Beleza?

Essa Specification é tipo um padrão de projeto que deixa você fazer umas consultas maneiras com a JPA Criteria API. Basicamente, tu consegue montar tuas buscas baseadas em condições que são definidas na hora que o código tá rodando.

Por exemplo, se tu tem uma entidade chamada Produto com uns atributos como nome, descricao, preco e categoria, dá pra criar um Specification pra cada um desses, saca só:

public class ProdutoSpecification {
    public static Specification<Produto> nome(String nome) {
        return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("nome"), "%" + nome + "%");
    }

    public static Specification<Produto> descricao(String descricao) {
        return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("descricao"), "%" + descricao + "%");
    }

    public static Specification<Produto> preco(BigDecimal preco) {
        return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("preco"), preco);
    }

    public static Specification<Produto> categoria(String categoria) {
        return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("categoria"), categoria);
    }
}

E aí, lá na camada de serviço, tu joga essas Specifications no método findAll do teu repositório, tipo assim:

public List<Produto> buscar(String nome, String descricao, BigDecimal preco, String categoria) {
    return produtoRepository.findAll(Specification
            .where(nome(nome))
            .or(descricao(descricao))
            .or(preco(preco))
            .or(categoria(categoria)));
}

Olha só, o findAll vai te trazer todos os produtos que batem com pelo menos uma dessas condições. Se quiser que todos os parâmetros contem na busca, só trocar o .or por .and.

Valeu!

Eu gostei muito da resposta acima com o uso da Specification, deixa a solução bem elegante.

Não sei se a resposta que darei aqui é a mais recomendada, caso não seja, por favor, me corrijam, mas eu costumo resolver esse problema usando o próprio JPQL.

Resumidamente, para cada parâmetro da busca que está sendo realizada, é feita uma verificação se o parâmetro foi passado como NULL, caso sim, ignora e segue para o próximo, caso não, é feita a comparação.

Tomando o mesmo exemplo acima de uma classe Produto com os atributos nome, descricao, preco e categoria, eu costumo solucionar essa busca assim:

SELECT p FROM Produto p WHERE (:nome IS NULL OR p.nome ILIKE %:nome%) AND (:descricao IS NULL OR p.descricao ILIKE %:descricao%) AND (:preco IS NULL OR p.preco = :preco) AND (:categoria IS NULL OR p.categoria ILIKE %:categoria%)

Espero ter ajudado.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software