Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Consulta feita no final do vídeo e LAZY vs EAGER

Boa tarde galera,

Gostaria de levantar um questionamento sobre a consulta realizada no final do vídeo da aula 6 - Relacionamentos bidirecionais e o comportamento Lazy. Me perdoem se eu estiver deixando passar algo óbvio ou se mais para frente no curso isso ficará mais claro.

Observem que até aquele momento, as entidades envolvidas estão relacionadas conforme abaixo:

Movimentacao.java tem:

@ManyToOne
private Conta conta;

E Conta.java tem:

@OneToMany(mappedBy="conta", fetch=FetchType.LAZY)
private List<Movimentacao> movimentacoes;

Então executamos a seguinte query:

Query query = em.createQuery("select c from Conta c");
List<Conta> contas = query.getResultList();

Se habilitarmos a opção show_sql, veremos que o Hibernate executou apenas a consulta abaixo e que o resultado são os 5 registros de Conta que existem no banco, exatamente como o esperado. Se chamarmos o getMovimentacoes() de qualquer uma destas contas, veremos que será executado a consulta para trazer as movimentações dela.

// Traz as 5 contas
select
        conta0_.id as id1_0_,
        conta0_.agencia as agencia2_0_,
        conta0_.banco as banco3_0_,
        conta0_.numero as numero4_0_,
        conta0_.titular as titular5_0_ 
    from
        Conta conta0_

// Traz as Movimentações de uma Conta
select
        movimentac0_.conta_id as conta_id6_1_0_,
        movimentac0_.id as id1_1_0_,
        movimentac0_.id as id1_1_1_,
        movimentac0_.conta_id as conta_id6_1_1_,
        movimentac0_.data as data2_1_1_,
        movimentac0_.descricao as descrica3_1_1_,
        movimentac0_.tipo as tipo4_1_1_,
        movimentac0_.valor as valor5_1_1_ 
    from
        Movimentacao movimentac0_ 
    where
        movimentac0_.conta_id=?

Agora quando executamos a query abaixo, que seria para fazer ser EAGER a consulta, sendo que o relacionamento é LAZY.

Query query = em.createQuery("select c from Conta c join fetch c.movimentacoes");
List<Conta> contas = query.getResultList();

Eu imaginei, baseado no que o instrutor fala, que voltaria uma lista com as 5 mesmas Contas, contudo suas Movimentacoes já viriam preenchidas. E isso se refletiria através de 6 consultas (1 + N, sendo 1 consulta para retornar as 5 Contas, e uma consulta para retornar a Lista de Movimentações de cada Conta).

Mas o que acontece não é isso. O retorno desta Query é uma Lista de Contas com 12 registros, onde a consulta gerada pelo Hibernate é esta abaixo:

select
        conta0_.id as id1_0_0_,
        movimentac1_.id as id1_1_1_,
        conta0_.agencia as agencia2_0_0_,
        conta0_.banco as banco3_0_0_,
        conta0_.numero as numero4_0_0_,
        conta0_.titular as titular5_0_0_,
        movimentac1_.conta_id as conta_id6_1_1_,
        movimentac1_.data as data2_1_1_,
        movimentac1_.descricao as descrica3_1_1_,
        movimentac1_.tipo as tipo4_1_1_,
        movimentac1_.valor as valor5_1_1_,
        movimentac1_.conta_id as conta_id6_1_0__,
        movimentac1_.id as id1_1_0__ 
    from
        Conta conta0_ 
    inner join
        Movimentacao movimentac1_ 
            on conta0_.id=movimentac1_.conta_id

Com isso, acaba sendo gerado como resultado, ao invés de 5 objetos Conta, cada um com sua Lista Movimentações já carregada (Que é o sentido do conceito de EAGER para mim), temos 12 Objetos Conta, repetindo cada Conta o número de vezes igual à quantidade de movimentações que elas tinham. Ou seja, Conta 1 tinha 4 Movimentações, nessa lista retornada tem 4 Contas 1, e elas todas tem a sua lista Movimentações preenchida. Se prestarem atenção no console do Instrutor, vai dar pra ver que na execução dele também ocorreu isso, voltaram 12 registros pois tem print com o sysout.

Não sei se consegui explicar direito esta última parte. Qualquer dúvida me perguntem. Mas então, era pra ser assim mesmo? Era pra ocorrer uma combinação dos dados de cada tabela?? Não me parece fazer sentido, baseado em como é explicado.

Notem que, se formos no mapeamento da lista de movimentações na classe Conta, e alterarmos para EAGER o fetchType, e depois executarmos uma Query comum sem o join fetch, terá o comportamento esperado de EAGER, ou seja, o retorno será uma lista com as 5 contas (1 consulta), e cada Conta já terá sua lista de Movimentações carregada (+5 consultas).

Agora quando deixamos LAZY e usamos este join fetch mostrado, não é a mesma coisa o resultado, então ele não serviu para "forçar um relacionamento LAZY a agir como EAGER em uma consulta". Foi outro comportamento.

Deixo também a pergunta, se eu tiver o relacionamento LAZY, e quiser que apenas uma consulta se comporte como EAGER, mantendo o resultado que teria se fosse um relacionamento EAGER, teria jeito?

Desculpem pelo tamanho do post. Não consegui resumir muito.

Abraços.

1 resposta
solução!

Encontrei que mais para frente no material ele fala que com o uso do Distinct os registros repetidos são eliminados. A informação certa está no material do curso. Talvez apenas o momento que é apresentada não seja o mais propício, ele poderia ter falado no vídeo mesmo quando fez a consulta, já ter comentado desta "falha" no resultado e já comentar a solução.

Obrigado.

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