Erro com Hibernate + Spring - "could not initialize proxy - the owning Session was closed"

Olá!

Pessoal, estou usando o Spring para me ajudar a trabalhar com o Hibernate, mas estou precisando criar um método para excluir o relacionamento entre duas entidades e depois remontar esse relacionamento. Na aplicação (web) eu tenho duas listas, onde uma contem os Subtemas e na outra os Subtemas que estão relacionados a um Tema. Quando eu submeto o formulário, eu envio os ids dos Subtemas. No servidor, todos os Subtemas relacionados ao Tema são removidos, os ids recebidos são iterados, faz-se uma pesquisa para cada id e vou adicionando de novo no Tema. Por fim, atualizo o Tema.
Meu problema está na hora que tento alterar algo no Tema. O primeiro erro vem quando eu tento limpar o Set que mantém os Subtemas no tema. Vejam o código:

hTemplate é um HibernateTemplate e idsSubtemasRelacionados é uma String que contém todos os ids dos Subtemas a serem relacionados, separados por traço.

[code]
if ( !idsSubtemasRelacionados.equals( “” ) ) {

o = ( Tema ) hTemplate.load( Tema.class, 
        Long.parseLong( request.getParameter( "id" ) ) );

// retira todos os subtemas
// o erro acontece aqui, quanto teto mudar algo do objeto recebido.
o.getSubtemas().clear();

String[] idsSubtemas = idsSubtemasRelacionados.split( "-" );

for ( String i : idsSubtemas ) {

    // pesquisa cada subtema e insere no tema
    o.getSubtemas().add( ( Subtema ) hTemplate.load( Subtema.class, Long.parseLong( i ) ) );

}

hTemplate.update( o );

}[/code]

Tema e Subtema estão usando um relacionamento ManyToMany, ou seja, a tabela que liga os dois é gerada pelo Hibernate e cada um está mapeado dentro do outro por um Set. O método equals está implementado tanto em Tema quanto em Subtema.

Abraço!

Faltou falar do erro…

Então, no e.getSubtemas().clear() é gerada uma excessão.

could not initialize proxy - the owning Session was closed org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60) org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111) org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:140) br.com.ynner.ynnerlib.entidades.Tema$$EnhancerByCGLIB$$a798a758.getSubtemas(<generated>) br.com.ynner.ynnerlib.servlets.TemaServlet.processRequest(TemaServlet.java:66) << LINHA DO e.getSubtemas.clear() br.com.ynner.ynnerlib.servlets.TemaServlet.doPost(TemaServlet.java:100) javax.servlet.http.HttpServlet.service(HttpServlet.java:709) javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

Estou usando Servlets devido a especificação que me foi passada.

Obrigado!

davidbuzatto ,

poderia mostrar o mapeamento das entidades envolvidas?

Mas adiantando, isso parece ser algo relacionado a “mappedBy” ou “inverse”… Mas acho que vendo os mapeamentos, podemos ajudar melhor… :slight_smile:

Abraço…

Olá!

Estão ai os mapeamentos (estou usando annotations)

[code]
@Entity
public class Subtema {

@Id
@GeneratedValue
private long id;

@Length( max = 50 )
@NotNull
@NotEmpty
private String descricao;

@ManyToMany
private Set< Tema > temas;

@ManyToMany
private Set< Materia > materias;

}

@Entity
public class Tema {

@Id
@GeneratedValue
private long id;

@Length( max = 50 )
@NotNull
@NotEmpty
private String descricao;

@ManyToMany( mappedBy = "temas" )
private Set< Subtema > subtemas;

@ManyToMany
private Set< Materia > materias;

}[/code]

Já inverti o mapeamento (usando o mappedBy invertido, ou seja, dentro da entidade Tema), mas tbm não funcionou.

Certo…

Tente inicializar seus atributos

private Set<Subtema> subtemas = new HashSet<Subtema>();

Ou ao invés de dar um .clear(), vc não faz o seguinte:

o.setSubtemas(new HashSet<Subtema>()); 

Ou outra implementação da interface Set…

Olá!

Obrigado pelas dicas, eu testei as mesmas mesmo tendo certeza que não é isso.
O problema está que o Spring não está mantendo a sessão aberta, pois se eu altero algo no objeto ele não deixa, isso está ligado a qualquer atributo e não só ao Set. Enfim, obrigado pela ajuda.

Se alguém tiver outra sugestão estou aguardando.

Até mais!

Andei pesquisando, e como o próprio erro diz, é pq a sessão do Hibernate já está fechada, e como estou usando lazy loading dá esse erro. O mais estranho é que mudei todos os relacionamentos para FetchType.EAGER e mesmo assim não funciona, o erro permanece.
Teria como configurar para que no Spring a sessão fique aberta e depois eu a feche?

Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :frowning:

[quote=davidbuzatto]Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :([/quote]

Amigo, o Spring resolve este problema. Tudo que tem que fazer é injetar a session por ele. Fazer manualmente é muito tosco e vira um baita trabalho desnecessário.
Vá ao site do Urubatan:

www.urubatan.com.br

Lá existem exemplos com Spring e o Annotation dele. Muito bom e resolve seu problema.

Abraços e bons códigos ai.

[quote=ajaxinaction][quote=davidbuzatto]Já estou quase montando a entidade fraca na mão :smiley:
Ninguém tem uma solução? Eu não queria abrir mão do Spring :([/quote]

Amigo, o Spring resolve este problema. Tudo que tem que fazer é injetar a session por ele. Fazer manualmente é muito tosco e vira um baita trabalho desnecessário.
Vá ao site do Urubatan:

www.urubatan.com.br

Lá existem exemplos com Spring e o Annotation dele. Muito bom e resolve seu problema.

Abraços e bons códigos ai.[/quote]

Valeu! Vou dar uma olhada!

Procura sobre OpenSessionInViewFilter ou melhor usa a solução que o kenobi postou.

http://guj.com.br/posts/list/43846.java#231495

Valeu rodrigo, agora está dando certo!
Só que não está atualizando no banco :frowning:
Mas o erro foi embora :smiley:
Abraço!

Bem… Não funcionou…
Testei os cadastrados que já estava funcionando, e agora eles pararam de funcionar, os objetos não são mais atualizados tbm…

Consegui!

Usando o OpenSessionInViewFilter (post do Kenobi) eu tive que a partir do meu Hibernate Template obter a sessão e abrir uma transação e dar commit na mesma. Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.

Outra coisa que estava errada era o mapeamento que estava invertido em TODOS os meus relacionamentos :D, mas isso não tem nada haver com o “erro” do Spring.

Valeu pessoal!

[quote=davidbuzatto] Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.
[/quote]
vc configurou a transação no applicationContext?

[]´s

[quote=jgbt][quote=davidbuzatto] Porque o transaction manager não funciona? Fui obrigado a criar, iniciar e comitar a transação.
[/quote]
vc configurou a transação no applicationContext?

[]´s[/quote]

Criei sim.

Olha só:

[code]
.
.
.

<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/banco"/>
<property name="username" value="usuario"/>
<property name="password" value="senha"/>
<property name="initialSize" value="5"/>
<property name="maxActive" value="10"/>
<property name="dataSource" ref="dataSource" />

<!-- Classes -->
<property name="annotatedClasses">
    <list>
        <value>entidades....</value>
    </list>
</property>

<property name="hibernateProperties">
    <props>
        <!-- Buscando no arquivo de properties -->
        <prop key="hibernate.dialect">${hibernate.dialect}</prop>
    </props>
</property>



. . .[/code]

Faltou algum detalhe?

sim :smiley:

vc precisa dizer p/ o Spring qual objeto/metodo precisa de transação e qual tipo de transação vc vai aplicar.
de uma olhada nesses links:

http://static.springframework.org/spring/docs/2.0.x/reference/orm.html#orm-jpa-tx
http://www.onjava.com/pub/a/onjava/2005/05/18/swingxactions.html
http://static.springframework.org/spring/docs/1.2.x/reference/transaction.html

qualquer coisa que não entender avisa.

[]´s

Hummm entendi!

Vou dar uma olhada!

Obrigado!