quarta-feira, 10 de março de 2021

JPA 2.1 - Criteria Builder, evitando query adicional causada por FetchType Lazy (lazy-loading)

 Hoje durante a utilização da api criteria para consultas dinâmicas enquanto realizava um curso, me deparei com uma coisa bem chata, no qual eu possuo 3 beans.
  • Estado
  • Cidade
  • Usuário
Ocorria o seguinte inconveniente, devido essa consulta ser usada em filtros decidi usar o CriteriaBuilder pela facilidade em criar  dinamicamente as consultas, porem todas as vezes que eu realizava uma consulta sempre recebia duas consultas adicionais, uma para Cidade e outra para Estado. E antes que me perguntem sim! marquei como lazy essas relações e não desejo nem quero que sejam JoinType Eager sempre, porem ao usar o CriteriaBuilder ele ignora completamente e volta a usar o lazy-loading.

  
    select
        cliente0_.codigo as codigo1_2_,
        cliente0_.cpf_cnpj as cpf_cnpj2_2_,
        cliente0_.email as email3_2_,
        cliente0_.cep as cep4_2_,
        cliente0_.codigo_cidade as codigo_11_2_,
        cliente0_.complemento as compleme5_2_,
        cliente0_.logradouro as logradou6_2_,
        cliente0_.numero as numero7_2_,
        cliente0_.nome as nome8_2_,
        cliente0_.telefone as telefone9_2_,
        cliente0_.tipo_pessoa as tipo_pe10_2_ 
    from
        cliente cliente0_ 
    where
        1=1 limit ?;

    select
        cidade0_.codigo as codigo1_1_0_,
        cidade0_.codigo_estado as codigo_e3_1_0_,
        cidade0_.nome as nome2_1_0_ 
    from
        cidade cidade0_ 
    where
        cidade0_.codigo=?;

    select
        estado0_.codigo as codigo1_3_0_,
        estado0_.nome as nome2_3_0_,
        estado0_.sigla as sigla3_3_0_ 
    from
        estado estado0_ 
    where
        estado0_.codigo=?

O que de fato não é nem de longe ideal para um bom desempenho, mas então oque fazer ? será que existe uma forma de incorporar na primeira query as duas adicionais ? E a resposta é sim! basta fazer o fetch ,  nas relações que deseja evitar as consultas adicionais, mesma coisa que fazemos no HQL.

   Root cliente = querie.from(Cliente.class);           
            
   cliente.fetch(Cliente_.ENDERECO)//Representa o endereço 
          .fetch(Endereco_.CIDADE, JoinType.LEFT)//Realiza o Fetch de Cliente com Cidade
          .fetch(Cidade_.ESTADO, JoinType.LEFT);  //Realiza o Fetch da Cidade com estado
  
A partir de agora a consulta gerada é a seguinte.
  
    select
        cliente0_.codigo as codigo1_2_0_,
        cidade1_.codigo as codigo1_1_1_,
        estado2_.codigo as codigo1_3_2_,
        cliente0_.cpf_cnpj as cpf_cnpj2_2_0_,
        cliente0_.email as email3_2_0_,
        cliente0_.cep as cep4_2_0_,
        cliente0_.codigo_cidade as codigo_11_2_0_,
        cliente0_.complemento as compleme5_2_0_,
        cliente0_.logradouro as logradou6_2_0_,
        cliente0_.numero as numero7_2_0_,
        cliente0_.nome as nome8_2_0_,
        cliente0_.telefone as telefone9_2_0_,
        cliente0_.tipo_pessoa as tipo_pe10_2_0_,
        cidade1_.codigo_estado as codigo_e3_1_1_,
        cidade1_.nome as nome2_1_1_,
        estado2_.nome as nome2_3_2_,
        estado2_.sigla as sigla3_3_2_ 
    from
        cliente cliente0_ 
    left outer join
        cidade cidade1_ 
            on cliente0_.codigo_cidade=cidade1_.codigo 
    left outer join
        estado estado2_ 
            on cidade1_.codigo_estado=estado2_.codigo 
    where
        1=1 limit ?

Espero ter ajudado pessoas que assim como eu tiveram muitos problemas,  para conseguir realizar esse simples procedimento assim como era feito no HQL.

Nenhum comentário:

Postar um comentário