JPA Lazy Load too lazy!
Galera estou desenvolvendo uma aplicação JPA + JSF, baseado nos cursos do Dyego Carmo, e me deparei com um problema, que ao meu ver é um BUG, no lazy load do JPA. Muito, muito estranho!
Para adiantar o problema é o seguinte:Fiz um método no DAO para carregar uma propriedade lazy da entidade.Quando rodo um teste de unidade onde é necessário carregar essa propriedade, o JPA acusa:failed to lazily initialize a collection of role: br.com.myfinances.entity.Parcela.lancamentoList, no session or session was closedPorém quando boto pra DEPURAR o teste, advinhem só! Ele carrega!! :-O Funciona sem erro nenhum!
Vou postar abaixo as partes necessárias do código...(Para contextualizar vocês, trata-se de uma aplicação financeira)
Tenho uma classe Conta que possui uma propriedade lancamentoList no modo lazy:
Tenho um ContaDAO, onde botei um método para carregar essa propriedade dentro duma sessão aberta:
(lembrando que o método JPAUtil.getInstance().getEntityManager() retorna um EM com transação aberta)
Daí no teste de unidade tenho a seguinte chamada:
E quando executo o teste..... PAU!Ele acusa o erro mostrado no início, dizendo que não foi possível carregar a propriedade.
Mas daí eu fui debugar para ver porque estava ocorrendo esse maldito erro.Então lá vou eu, de F8 em F8, executando passo-a-passo esse método. De repente, terminei a depuração e o teste foi executado com sucesso!
Náaa, não é possível!!! Executei mais 20 vezes para acreditar que isso estava ocorrendo e está!Inclusive na própria depuração se eu mandar executar de vez ele acusa o erro.Só funciona quando eu vou passo-a-passo no método, devagarzinho.Pois é, esse Lazy Mode do JPA está muuuito lazy! (Ô meu rei... Ó paí ó!)
Já tentei algumas maneiras para tentar dar uma "freada" no método mas sem sucesso.
O que vocês sugerem?Já viram isso?
Abraços.
att.Jovan Andrade
Para adiantar o problema é o seguinte:Fiz um método no DAO para carregar uma propriedade lazy da entidade.Quando rodo um teste de unidade onde é necessário carregar essa propriedade, o JPA acusa:failed to lazily initialize a collection of role: br.com.myfinances.entity.Parcela.lancamentoList, no session or session was closedPorém quando boto pra DEPURAR o teste, advinhem só! Ele carrega!! :-O Funciona sem erro nenhum!
Vou postar abaixo as partes necessárias do código...(Para contextualizar vocês, trata-se de uma aplicação financeira)
Tenho uma classe Conta que possui uma propriedade lancamentoList no modo lazy:
@OneToMany(mappedBy = "conta") private List<Lancamento> lancamentoList;
Tenho um ContaDAO, onde botei um método para carregar essa propriedade dentro duma sessão aberta:
public List<Lancamento> loadLancamento(Conta conta) { EntityManager em = JPAUtil.getInstance().getEntityManager(); conta = em.getReference(Conta.class, conta.getIdConta()); List<Lancamento> toReturn = conta.getLancamentoList(); em.close(); return toReturn; }(lembrando que o método JPAUtil.getInstance().getEntityManager() retorna um EM com transação aberta)
Daí no teste de unidade tenho a seguinte chamada:
//-- Recuperando LANÇAMENTO a partir da Conta List<Lancamento> lancamentoList = contaDAO.loadLancamento(conta); Lancamento lancamento = lancamentoList.get(0);
E quando executo o teste..... PAU!Ele acusa o erro mostrado no início, dizendo que não foi possível carregar a propriedade.
Mas daí eu fui debugar para ver porque estava ocorrendo esse maldito erro.Então lá vou eu, de F8 em F8, executando passo-a-passo esse método. De repente, terminei a depuração e o teste foi executado com sucesso!
Náaa, não é possível!!! Executei mais 20 vezes para acreditar que isso estava ocorrendo e está!Inclusive na própria depuração se eu mandar executar de vez ele acusa o erro.Só funciona quando eu vou passo-a-passo no método, devagarzinho.Pois é, esse Lazy Mode do JPA está muuuito lazy! (Ô meu rei... Ó paí ó!)
Já tentei algumas maneiras para tentar dar uma "freada" no método mas sem sucesso.
O que vocês sugerem?Já viram isso?
Abraços.
att.Jovan Andrade
Jovan Junior
Curtidas 0
Respostas
Jovan Junior
05/05/2011
Resolvi o problema ajustando o modo de recuperação do objeto no DAO. Troquei de getReference(...) para find(...).
Para visualizar:
Mesmo assim, continuo intrigado com isso. Mesmo usando o getReference(...) não deveria dar erro. (Ao meu ver)O JPA teria que esperar o objeto carregar para depois partir para a próxima execução. Por que ele não faz isso?
Será que o JPA está sendo burro ao ponto de fazer duas cargas nesse caso (1º carregar o objeto sem a propriedade, 2º carregar a propriedade)?
Na minha cabeça, ao usar o getReference(...), eu estaria poupando uma ida a mais no banco desnecessária.No caso ele deveria, trazer o objeto completo, já com a propriedade, pois solicitei a propriedade diretamente.(Se ainda não carregou o objeto, carregue com tudo que precisa ora!)
Alguém pode me desmistificar esse caso com certeza?
att.Jovan Andrade
Para visualizar:
public List<Lancamento> loadLancamento(Conta conta) { EntityManager em = JPAUtil.getInstance().getEntityManager(); //conta = em.getReference(Conta.class, conta.getIdConta()); conta = em.find(Conta.class, conta.getIdConta()); List<Lancamento> toReturn = conta.getLancamentoList(); em.close(); return toReturn; }Mesmo assim, continuo intrigado com isso. Mesmo usando o getReference(...) não deveria dar erro. (Ao meu ver)O JPA teria que esperar o objeto carregar para depois partir para a próxima execução. Por que ele não faz isso?
Será que o JPA está sendo burro ao ponto de fazer duas cargas nesse caso (1º carregar o objeto sem a propriedade, 2º carregar a propriedade)?
Na minha cabeça, ao usar o getReference(...), eu estaria poupando uma ida a mais no banco desnecessária.No caso ele deveria, trazer o objeto completo, já com a propriedade, pois solicitei a propriedade diretamente.(Se ainda não carregou o objeto, carregue com tudo que precisa ora!)
Alguém pode me desmistificar esse caso com certeza?
att.Jovan Andrade
GOSTEI 0
Davi Costa
05/05/2011
GOSTEI 0
Davi Costa
05/05/2011
GOSTEI 0
Dyego Carmo
05/05/2011
Uma coisa que tenho observado é que o EclipseLINK funciona melhor que o Hibernate em casos de controlar os exceptions lazy...
em todo caso,
Resolvido ? Favor fechar :)
em todo caso,
Resolvido ? Favor fechar :)
GOSTEI 0
Jovan Junior
05/05/2011
Resolver, resolvi, como postei acima.
Porém não me foi explicado por que quando uso o getReference() não funciona mas quando uso o getEntity() funciona.
Sendo que o que acontece com o getReference() não é que não funciona, mas na verdade é "lerdeza" ou preguiça para retornar a lista solicitada.Pois quando solicito a lista rodando a aplicação normalmente dá o erro de LazyException, mas quando rodo no modo debug, que dou um tempo para receber a lista, ela vem e não ocorre erro nenhum, funciona perfeitamente.
Porém não me foi explicado por que quando uso o getReference() não funciona mas quando uso o getEntity() funciona.
Sendo que o que acontece com o getReference() não é que não funciona, mas na verdade é "lerdeza" ou preguiça para retornar a lista solicitada.Pois quando solicito a lista rodando a aplicação normalmente dá o erro de LazyException, mas quando rodo no modo debug, que dou um tempo para receber a lista, ela vem e não ocorre erro nenhum, funciona perfeitamente.
GOSTEI 0
Jovan Junior
05/05/2011
corrigindo o que escrevi acima, não é getEntity mas find, como vocês podem ver no código.
GOSTEI 0