Hibernate. problema ao iniciar associacao lazy

Tenho uma colecao que é atributo de um objeto e é configurada com lazy=true no mapeamento do hibernate.
Seria Tesoura.materiais.
O meu método GerenciadorTesoura.getTodasTesouras() devolve uma coleção de todas tesouras do banco. Elas sao apresentadas em uma de pesquisa. Se a pessoa abrir a tela de edição, uma dessas tesouras sao apresentada na tela de edição. Na tela de edição, preciso iniciar a coleção materiais da tesoura, pois lá vou adicionar novos materiais ou excluir.
O problema é que para mim referenciar materiais, o objeto tesoura precisa estar ligado a uma secao aberta. Mas o GerenciadorTesoura.getTodasTerouras, devolve a colecao de tesouras e já fecha a secao. Então, tenho que dar um jeito de iniciar a colecao materiais de tesoura, antes de utilizá-la. Pensei em fazer a solução abaixo. O que vocês acham ou recomendam para essa situação?

protected void acaoAdicionar() { if (tesoura ==null) acaoSalvar(); Session session = HibernateUtil.getSession(); Transaction trans = session.beginTransaction(); session.update(tesoura); Hibernate.initialize(tesoura.getMateriais()); trans.commit(); session.close(); new ControladorTelaEdicaoMaterialDaTesoura(tesoura); }

Opa cara, esse é um problema recorrente. Duas soluções:

  1. Carregue a colução toda logo de cara, sem lazy loading. Pode fazer isso assim:
Criteria c = session.createCriteria( Tesoura.class );
c.setFetchMode( "materiais", FetchMode.EAGER );
c.add( Expression.eq( "id", 1 ) );
Tesoura c = ( Tesoura ) c.list.get( 0 );
  1. Ou o jeito bonitão, se sua aplicação é web. É possível só fechar a sessão depois que a página foi renderizada. Se for o seu caso, diga.

Para carregar a coleção sem lazy é só tirar o lazy do mapeamento, não?

Eu tenho uma tela de pesquisa (aplicação swing). Ela pega uma lista de Tesouras. Eu abro a tela de edição e mando uma tesoura dessa lista para ela. Na tela de edição, tem uma tabela onde será mostrado os materiais da tesoura (tesoura.getMateriais). Sendo assim, já existe o objeto tesoura, que foi instanciado por uma sessao que já foi fechada.
Mas preciso entao abrir uma sessao e reassociar esse objeto a nova sessao para entao poder fazer o tesoura.getMateriais, para pode apresentar na minha tabela, para poder adicionar ou remover itens na lista de materiais.

Simplesmente tirar o lazy da declaração não adianta né cara? hehe muito provável que seja útil em outros casos.

E sua solução parece boa.

Tirando o lazy provavelmente adianta, mas ai eu perco o recurso de só fazer a consulta quando for necessário.
Se eu tirar o lazy, na minha tela de pesquisa, onde eu mostro todas as tesouras, ele já vai pegar os materiais de todas as tesouras, sem ter necessidade.

Que solução que parece boa? Por enquanto tá sem solução :?
Preciso dar um jeito de associar meu objeto que foi obtido por uma sessao que já está fechada a uma nova sessao.

Qual versão do Hibernate está usando? Se for 3.x, há esse método aqui

/**
  * Make a transient instance persistent. This operation cascades to associated 
  * instances if the association is mapped with <tt>cascade="persist"</tt>.
  * The semantics of this method are defined by JSR-220.
  * 
  * @param object a transient instance to be made persistent
  */
public void persist(Object object) throws HibernateException;

Se estiver usando 2.x, abre a sessão de novo e faz o load no objeto novamente, desta fez usando o lance de setFetchMode.

Eu tentei, mas está dando esse erro: org.hibernate.PersistentObjectException: detached entity passed to persist: null

Veja o que fiz:

public ControladorTelaEdicaoTesoura(Tesoura tesoura) { super(); visao.setTitle("Tesoura"); visaoTesoura = (TelaEdicaoTesoura)visao; this.tesoura = tesoura; visaoTesoura.setDescricaoTesoura(tesoura.getDescricao()); Session session = HibernateUtil.getSession(); Transaction trans = session.beginTransaction(); session.persist(tesoura); Hibernate.initialize(tesoura.getMateriais()); visaoTesoura.getPainelTabela().getTableModelPadrao().setLinhas(tesoura.getMateriais()); visao.setVisible(true); trans.commit(); session.close(); }

Resolvi o problema trocando persist para session.saveOrUpdate(tesoura).