Bom dia amigos.
Estou com um problema para validar o nosso cadastro de usuarios, através do JPA Criteria, contra as tabelas de CEP fornecidas pelo correio e descobrir quantos clientes possuem o cep inválido. As tabelas principais do correio são a de logradouro e localidade (esta guarda os de municipios com cep único). Esta consulta seria resolvida de maneira simples com SQL.
SELECT a.* FROM YY_CLIENTE.CLIENTE A
LEFT JOIN YY_CEP.LOG_LOCALIDADE B ON A.ENDERECO_CEP = B.CEP
LEFT JOIN YY_CEP.LOG_LOGRADOURO C on A.ENDERECO_CEP = C.CEP
WHERE (B.CEP IS NULL AND C.CEP IS NULL) and a.bloqueio_cod = 31;
Porém, a arquitetura da empresa não me permite usar JDBC e nem queries nativas. Aí começam os meus problemas…
Do jeito que as classes foram modeladas, eu não tenho um Path que relaciona o cep’s das tabelas de cep para o cep do endereco do cliente, ou seja, pelo Criteria eu não tenho como fazer o Join. A solução seria então fazer uma subquerie:
SELECT count(a.id) FROM YY_CLIENTE.CLIENTE A
WHERE a.ENDERECO_CEP not in (select cep from YY_CEP.LOG_LOCALIDADE where cep is not null)
and a.ENDERECO_CEP not in (select cep from YY_CEP.LOG_LOGRADOURO where cep is not null)
and a.bloqueio_cod = 31
Até aí nem um mistério, o problema está quando uso o JPA
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<Cliente> rt = cq.from(Cliente.class);
Path<Long> cep = rt.get(Cliente_.endereco).get(EnderecoImovel_.cep);
cq.select(cb.count(rt));
Subquery<Long> subquery = cq.subquery(Long.class);
Root<CepLogradouro>subRoot = subquery.from(CepLogradouro.class);
subquery.select(subRoot.get(CepLogradouro_.cep).as(Long.class));
Subquery<Long> subquery2 = cq.subquery(Long.class);
Root<CepLocalidade>subRoot2 = subquery.from(CepLocalidade.class);
subquery2.select(subRoot2.get(CepLocalidade_.cep).as(Long.class));
cq.where(
cb.not(cb.in(cep).value(subquery)),
cb.not(cb.in(cep).value(subquery2)),
cb.equal(rt.get(Cliente_.bloqueioCod), cb.literal("31"))
Long count = entityManager.createQuery(cq).getSingleResult();
);
Este código compila sem problemas, porém o SQL que é gerado está errado
Como podem reparar a estrutura das subqueries não é montada de maneira correta. A tabela da segunda subquey é colocada junto com a primeira subquery.
Alguem tem alguma dica do que estou fazendo de errado?