Lazy loading e DAO

Olá pessoal!
Tenho uma aplicação em Hibernate que está dividida em camadas. Uma das camadas é a DAO.
Acontece que todos os métodos das classes DAO abrem e fecham sessões, mas é preciso exibir os dados na GUI. Alguns desses dados pertencem a relacionamentos 1-N ou N-N, ou seja, são carregados no modo Lazy, o que melhorou bastante o desempenho de minha aplicação.
Então, como faço para recuperar os dados do relacionamento, mantendo a camada DAO, sem reassociar objetos a outras sessões na GUI?

Vocẽ poderia iniciar os sets que estão com lazy na consulta.
Ficaria assim:

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.EAGER)
    .setFetchMode("kittens", FetchMode.EAGER)
    .list();

Tirei este da documentacao no seguinte link:http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html

Pensei que existisse outra forma de fazer isso.
Então, se é assim, agradeço!
Até

O ideal é que você procure pelo padrão de projeto Open Session in View…
Nesse link você encontrar mais informações sobre ele: http://community.jboss.org/wiki/OpenSessioninView

Valeu

Sua aplicação e desktop ou web?

É desktop e só estou usando o Hibernate de framework

Então a segestão do OpenSessionView não funciona ou existe de configura-lo em projetos desktop?

Quanto ao OpenSessionInView estou dando uma olhada. Pensei que fosse só pra Web.
Outro ponto interessante é que na documentação do Hibernate eles dizem que é desnecessário criar uma camada de DAO, a menos que a aplicação seja realmente complexa.
No meu caso acho bastante interessante, simplifica bastante o código.

Eu estava pensando em utilizar uma única sessão para a aplicação toda.
Na documentação eles dizem que não é recomendado por causa do uso excessivo de memória. O que vocês acham?

Não entendi seu problema, pois o hibernate preenche automaticamente os elementos lazy, só que ao contrário do FetchMode Eager, apenas quando são necessários. Uso até mesmo coleções lazy, e não tenho problemas em mostrar na tela um registro ou o resultado de uma consulta. A documentação do hibernate sugere que se use lazy quando possível, por razões de performance.

Não entendo sua necessidade de manter apenas uma sessão para toda a aplicação, o que é extremamente desaconselhável, se está pensando em manter objetos e evitar “idas” ao banco de dados, use cache de segundo nível.

Acontece que o hibernate só vai carregar os objetos Lazy quando eles forem acessados E a sessão associada ao objeto estiver no estado aberto (opened).
Como eu disse, minhas classes DAO possuem métodos que abrem e fecham sessões, ou seja, se eu dou um ClasseExemploDAO.get( id ), obtenho um objeto da classe ClasseExemplo associado a uma sessão que foi fechada ao fim da execução do método get da ClasseExemploDAO.
Como o amigo disse ali em cima, é interessante usar fetchMode.EAGER ou, na verdade, fetchMode.JOIN, como dito na documentação.
Em relação ao desempenho que citei acima, não é em relação a acessar o BD várias vezes, mas sim em relação a carregar todas as coleções que representam os relacionamentos (1-N ou N-N). Assim, se eu mantivesse uma unica sessão aberta para toda a vida da aplicação, não precisaria carregar explicitamente os objetos lazy, eles seriam carregados somente na hora de seu acesso, visto que, desta vez, a sessão estaria aberta.

Recentemente encontrei um blog de um alemão que encontrou o mesmo problema que o meu, e no final ele conclui que para aplicações stand-alone swing, é recomendável utilizar uma sessão por tela.
Ufa, falei tudo!

Assim, parece que o mais viável é fazer o que o amigo Daniel.F disse, usar o fetchMode.JOIN nas minhas classes DAO, assim, quando eu quiser, posso utilizar um outro método que retorna todos as coleções, sem o LAZY, de um determinado objeto.

Ok, eu na verdade uso o modelo sessão por view, e acabei respondendo pensando nesse modelo. Mas lembre-se que você também pode carregar manualmente com o comando Hibernate.initialize(MinhaClasse.getItens()).

Na verdade o Hibernate.initialize(obj) só pode ser usado para um objeto cuja a sessão ainda está aberta, caso contrário ocorrerá o LazyInitializationException novamente, e caímos no problema inicial.

Sim, mas se você executa o comando Hibernate.initialize(MinhaClasse.getItens()) antes de fechar a sessão, você poderá iterar sobre esta coleção quando a sessão for fechada.
Normalmente a melhor opção é inicializar todos os objetos que a view irá necessitar e então fechar a sessão.

Dessa eu não sabia. Vou testar e logo respondo.
Vlw!

O comando é Hibernate.initialize(objeto.getItens()), acabei colocando a classe sem perceber. Funciona quase como o FetchMode.EAGER, mas tem a vantagem de você poder ler a coleção de apenas um objeto, já usando o FetchMode.EAGER se você listar uma classe que possui uma coleção, ele irá carregar todas as coleções de cada um dos objetos listados.

Ou seja em muitos casos o FetchMode.EAGER é uma solução mais simples, mas em outros especialmente quando há coleções com muitos elementos, usar o Hibernate.initialize apenas no objeto desejado poderá trazer um ganho de performance.