Sua segunda solução ficou bem melhor do que a primeira, apesar da query ficar dificil de ler, como vc destacou.
De qualquer forma, como vc esta usando Spring Data, pode usar o Query by Example. Vc pode ler mais no link abaixo.
https://docs.spring.io/spring-data/jpa/reference/repositories/query-by-example.html
E este é um exemplo bem básico de como ficaria.
@Getter
@Setter
@Entity
@Table(name = "empresa")
class ParceiroEntity {
@Id
@Column(length = 14, nullable = false)
private String cpf;
@Column(length = 255, nullable = false)
private String nome;
@Column(length = 255, nullable = false)
private String estado;
@Column(length = 2, nullable = false)
private String uf;
@Column(nullable = false)
private Integer numeroFuncionarios;
@Column(nullable = false)
private Integer qtdFiliais;
}
@Getter
@Setter
class ParceiroRequestParams {
private String cpf;
private String nome;
private String estado;
private Integer numero;
}
interface ParceiroRepository extends JpaRepository<ParceiroEntity, String> {
}
@RestController
class ParceirosController {
@Autowired
private ParceiroRepository repository;
@GetMapping("/parceiros")
List<ParceiroEntity> getParceiros(ParceiroRequestParams params) {
var matcher = ExampleMatcher
.matching()
.withStringMatcher(StringMatcher.CONTAINING)
.withIgnoreNullValues();
var entity = new ParceiroEntity();
entity.setCpf(params.getCpf());
entity.setNome(params.getNome());
entity.setEstado(params.getEstado());
entity.setNumeroFuncionarios(params.getNumero());
var example = Example.of(entity, matcher);
return repository.findAll(example);
}
}
A JpaRepository
já estende a QueryByExampleExecutor
, então não precisamos fazer nenhuma alteração no nosso repository.
Basicamente, como o nome da funcionalidade sugere, a gente cria um exemplo de entidade que queremos trazer do banco.
Funciona bastante bem para vários casos, e é perfeito para este cenário que vc apresentou.
Outra opção é usar as specifications. Veja mais aqui:
https://docs.spring.io/spring-data/jpa/reference/jpa/specifications.html
Apesar de mais complexas, specifications são bastante poderosas!
Obrigado, não conhecia essas opções e gostei muito de usar ExampleMatcher
, só tive dificuldade na hora de lidar com valores do tipo int
.
Ao usar int
os valores foram iniciados automaticamente pelo Java com o valor 0
então minha query acabou ficando assim
Método com Matcher:
public List<ParceiroEntity> findBySearchDynamic(ParceiroRequestParams params){
ExampleMatcher matcher = ExampleMatcher.matching()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
.withIgnoreCase()
.withIgnoreNullValues();
ParceiroEntity entity = new ParceiroEntity(
params.getCpf(),
params.getNome(),
params.getEstado()
);
return repository.findAll(Example.of(entity, matcher));
}
Query JPA:
select
pe1_0.cpf,
pe1_0.estado,
pe1_0.nome,
pe1_0.numero_funcionarios,
pe1_0.qtd_filiais,
pe1_0.uf
from
empresa pe1_0
where
lower(pe1_0.nome) like ? escape '\'
and pe1_0.qtd_filiais=?
and pe1_0.numero_funcionarios=?
Neste exemplo na API eu informei como parâmetro apenas o campo nome
mas o Java inicializou os dois campos e int
e minha query tentou buscar por qtd_filiais = 0
e numero_funcionarios=0
o que fez minha busca retornar nenhum registro.
Bastou trocar o tipo dos campos de int
para Integer
que agora ele consegue validar campos nulos e funcionou muito bem nos testes que fiz.
Query com os capos qtdFiliais
e numeroFuncionarios
como Integer
:
select
pe1_0.cpf,
pe1_0.estado,
pe1_0.nome,
pe1_0.numero_funcionarios,
pe1_0.qtd_filiais,
pe1_0.uf
from
empresa pe1_0
where
lower(pe1_0.nome) like ? escape '\'
Em resumo o código ficou muito mais conciso, vou estudar melhor para ver as opções que tenho com ExampleMatcher
mas se encaixou perfeitamente no que eu precisava.