Could not initialize proxy - no Session

12 respostas
jonas.cant

Estou tendo esse problema ao inserir em uma tabela em que há relação com outra tabela. Por exemplo: tenho uma classe Apartamento, outra classe Setor e outra classe TipoApartamento. A classe Apartamento tem um atributo do tipo Setor e outro atributo do tipo TipoApartamento. Vejam os códigos abaixo:

package model;

import java.io.Serializable;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "setor")
public class Setor implements Serializable {

	@Id
	@GeneratedValue
	@Column(name = "id_setor")
	private Integer codigo;
	@Column(length = 50)
	private String descricao;
	@OneToMany(mappedBy = "setor")
	private List<Apartamento> apartamentos;

	public Integer getCodigo() {
		return codigo;
	}

	public void setCodigo(Integer codigo) {
		this.codigo = codigo;
	}

	public String getDescricao() {
		return descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}
		
	
	public List<Apartamento> getApartamentos() {
		return apartamentos;
	}

	public void setApartamentos(List<Apartamento> apartamentos) {
		this.apartamentos = apartamentos;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		result = prime * result + ((descricao == null) ? 0 : descricao.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Setor other = (Setor) obj;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		return true;
	}		

}
package model;

import java.io.Serializable;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "tipo_de_apartamento")
public class TipoApartamento implements Serializable {

	@Id
	@GeneratedValue
	@Column(name = "id_tipo_apartamento")
	private Integer codigo;
	@Column(length = 50)
	private String descricao;
	@OneToMany(mappedBy = "tipoApartamento")
	private List<Apartamento> apartamentos;	
	
	public TipoApartamento() {		
	}

	public Integer getCodigo() {
		return codigo;
	}

	public void setCodigo(Integer codigo) {
		this.codigo = codigo;
	}

	public String getDescricao() {
		return descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}	
	
	public List<Apartamento> getApartamentos() {
		return apartamentos;
	}

	public void setApartamentos(List<Apartamento> apartamentos) {
		this.apartamentos = apartamentos;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		result = prime * result + ((descricao == null) ? 0 : descricao.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		TipoApartamento other = (TipoApartamento) obj;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		return true;
	}	

}
package model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="apartamento")
public class Apartamento implements Serializable {

	@Id
	@GeneratedValue
	@Column(name = "id_apartamento")
	private Integer codigo;
	@Column(length = 50)
	private String descricao;
	private Integer ramal;
	@ManyToOne
	@JoinColumn(name = "id_setor")
	private Setor setor;
	@ManyToOne
	@JoinColumn(name = "id_tipo_apartamento")	
	private TipoApartamento tipoApartamento;		
	
	public Integer getCodigo() {
		return codigo;
	}

	public void setCodigo(Integer codigo) {
		this.codigo = codigo;
	}

	public String getDescricao() {
		return descricao;
	}

	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}

	public Integer getRamal() {
		return ramal;
	}

	public void setRamal(Integer ramal) {
		this.ramal = ramal;
	}

	public Setor getSetor() {
		return setor;
	}

	public void setSetor(Setor setor) {
		this.setor = setor;
	}

	public TipoApartamento getTipoApartamento() {
		return tipoApartamento;
	}

	public void setTipoApartamento(TipoApartamento tipoApartamento) {
		this.tipoApartamento = tipoApartamento;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		result = prime * result + ((descricao == null) ? 0 : descricao.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Apartamento other = (Apartamento) obj;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		return true;
	}	
	
}
package util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

	private static final SessionFactory session = buildSessionFactory();

	private HibernateUtil() {
	}	
	
	private static SessionFactory buildSessionFactory() {
		try {
			Configuration cfg = new Configuration();
			cfg.configure("hibernate.cfg.xml");
			return cfg.buildSessionFactory();
		} catch (Throwable t) {
			System.out.println("Ocorreu um erro: " + t);
			throw new ExceptionInInitializerError();
		}
	}
	
	public static SessionFactory getSession() {
		return session;
	}	
	
}

E agora a implementação do Dao:

package dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import util.HibernateUtil;

import model.Apartamento;

public class ApartamentoDaoImp implements ApartamentoDao {


	public void save(Apartamento apartamento) {
		Session session = HibernateUtil.getSession().openSession();
		Transaction t = session.beginTransaction();
		session.save(apartamento);
		t.commit();
		session.close();
	}


	public Apartamento getApartamento(long id) {
		Session session = HibernateUtil.getSession().openSession();
		Apartamento temp = (Apartamento) session.load(Apartamento.class, id);
		session.close();
		return temp;
	}


	public List<Apartamento> list() {
		Session session = HibernateUtil.getSession().openSession();
		Transaction t = session.beginTransaction();
		List lista = session.createQuery("from Apartamento").list();
		t.commit();
		session.close();
		return lista;
	}


	public void remove(Apartamento apartamento) {
		Session session = HibernateUtil.getSession().openSession();
		Transaction t = session.beginTransaction();
		session.delete(apartamento);
		t.commit();
		session.close();
	}

	public void update(Apartamento apartamento) {
		Session session = HibernateUtil.getSession().openSession();
		Transaction t = session.beginTransaction();
		session.update(apartamento);
		t.commit();
		session.close();
	}


	public Apartamento findById(Integer id) {
		Session session = HibernateUtil.getSession().openSession();
		Apartamento td = (Apartamento) session.load(Apartamento.class, id);
		session.close();
		return td;
	}

}

Página JSF para listar os apartamentos e para chamar uma tela (dialog) para cadastro:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dset">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui"> 
 
<h:body> 

	<ui:composition template="tpl.xhtml">
		<ui:define name="conteudo">

			<h:form prependId="false">
				<p:commandButton value="Novo" icon="ui-icon-star" actionListener="#{apartamentoController.prepararAdicionarApartamento}" update=":formCadApartamento:panelGridCadApartamento" oncomplete="dialogCadApartamento.show()"/>		    
			</h:form>

			<p:panel header="Apartamentos">
				<h:form id="formConApartamento">		
			        <p:dataTable id="tabela" var="apart" value="#{apartamentoController.listarApartamentos}"
			        	
			        	widgetVar="apartamentoesTable" emptyMessage="Nenhum apartamento encontrado!"
			        	filteredValue="#{apartamentoController.filteredApartamentos}"
			        
			        >
			            <p:column	            
			            	filterBy="#{apart.codigo}"
			            	filterMatchMode="contains"
			            >
			                <f:facet name="header">
			                    <h:outputText value="Código"/>
			                </f:facet>
			                <h:outputText value="#{apart.codigo}"/>
			            </p:column>
			            <p:column
			            	filterBy="#{apart.descricao}"
			            	filterMatchMode="contains"	            	            
			            >
			                <f:facet name="header">
			                    <h:outputText value="Descrição"/>
			                </f:facet>
			                <h:outputText value="#{apart.descricao}"/>
			            </p:column>
			            <p:column
			            	filterBy="#{apart.ramal}"
			            	filterMatchMode="contains"	            	            
			            >
			                <f:facet name="header">
			                    <h:outputText value="Ramal"/>
			                </f:facet>
			                <h:outputText value="#{apart.ramal}"/>
			            </p:column>
						<p:column>
			                <f:facet name="header">
			                    <h:outputText value="Setor"/>
			                </f:facet>
			                <h:outputText value="#{apart.setor.descricao}"/>
			            </p:column>
						<p:column>
			                <f:facet name="header">
			                    <h:outputText value="Tipo"/>
			                </f:facet>
			                <h:outputText value="#{apart.tipoApartamento.descricao}"/>
			            </p:column>			            
						<p:column>
						    <f:facet name="header">
						        <h:outputText value="Opções"/>
						    </f:facet>
						    <p:commandButton icon="ui-icon-pencil" actionListener="#{apartamentoController.prepararAlterarApartamento}" value="Alterar" update=":formCadApartamento:panelGridCadApartamento" oncomplete="dialogCadApartamento.show()"/>
	                        <p:commandButton icon="ui-icon-close" value="Excluir" update=":formExclusao:panelGridExclusao" oncomplete="confirmation.show()">
 								<f:setPropertyActionListener value="#{apart}" target="#{apartamentoController.apartamento}" />
							</p:commandButton>					    					    
						</p:column>		            		                       
			        </p:dataTable>	  
			        	       		         
				</h:form>
			</p:panel>
			
			
			
			<p:dialog header="Apartamento" widgetVar="dialogCadApartamento" resizable="false" modal="false" showEffect="slide" width="300" >	            
			     <h:form id="formCadApartamento">
			         <h:panelGrid id="panelGridCadApartamento" columns="2" style="margin-bottom:10px">	 
			             <h:outputLabel for="codigo" value="Código:" />
			             <h:inputText id="codigo" value="#{apartamentoController.apartamento.codigo}" disabled="true"/>	 
			             <h:outputLabel for="descricao" value="Descrição:" />
			             <h:inputText id="descricao" value="#{apartamentoController.apartamento.descricao}"/>	 	                    	                    
			             <h:outputLabel for="ramal" value="Ramal:" />
			             <h:inputText id="ramal" value="#{apartamentoController.apartamento.ramal}"/>	 	                    	                    


			             
						 <h:outputLabel for="setor" value="Setor:" />
						 <p:selectOneMenu id="setor" value="#{apartamentoController.apartamento.setor}" >
							<f:selectItem itemLabel="Selecione..." itemValue="" />
							<f:selectItems value="#{setorController.setores}" var="setor" itemLabel="#{setor.descricao}" itemValue="#{setor}" /> 												
						 </p:selectOneMenu>			             
			             

						 <h:outputLabel for="tipoApartamento" value="Tipo Apartamento:" />
						 <p:selectOneMenu id="tipoApartamento" value="#{apartamentoController.apartamento.tipoApartamento}" >
							<f:selectItem itemLabel="Selecione..." itemValue="" />
							<f:selectItems value="#{tipoApartamentoController.tiposApartamentos}" var="ta" itemLabel="#{ta.descricao}" itemValue="#{ta}" /> 												
						 </p:selectOneMenu>
			             
			             <p:commandButton icon="ui-icon-disk" id="commandButtonInserir" update=":formConApartamento:tabela" oncomplete="dialogCadApartamento.hide();" actionListener="#{apartamentoController.adicionarApartamento}" value="Inserir" rendered="#{apartamentoController.isInsercao}"/>
			             <p:commandButton icon="ui-icon-disk" id="commandButtonAlterar" update=":formConApartamento:tabela" oncomplete="dialogCadApartamento.hide();" actionListener="#{apartamentoController.alterarApartamento}" value="Alterar" rendered="#{apartamentoController.isAlteracao}"/>	 
			         </h:panelGrid>
			     </h:form>
			</p:dialog>			
			
			
			
			<p:dialog header="Confirmação" widgetVar="confirmation" resizable="false">
			     <h:form id="formExclusao">
			         <h:panelGrid id="panelGridExclusao" columns="3" style="margin-bottom:10px">	 
			             <h:outputLabel value="Confirma exclusão do registro?" />
						 <p:commandButton id="btnSim" value="Sim" oncomplete="confirmation.hide();" actionListener="#{apartamentoController.actExcluirApartamento}" update=":formConApartamento:tabela" />
                		 <p:commandButton id="btnNao" value="Não" onclick="confirmation.hide();" type="button"/>			           	 
			         </h:panelGrid>
			     </h:form>				
			</p:dialog>			
			

			
			
			
			

		</ui:define>
	</ui:composition>

</h:body> 
</html>

Na hora de preencher os dados para o cadastro e clicar no ‘Inserir’, no console aparece a mensagem “org.hibernate.LazyInitializationException: could not initialize proxy - no Session”. Isso acontece também por exemplo ao selecionar um país em um combobox em que há uma chamada para carregar uma lista de estados para outro combobox.

12 Respostas

DaniloAndrade

isso acontece quando a entidade que vc esta manipulando não esta mais sendo gerenciado pelo hibernate

no seu dao vc esta fechando a session nos metodos do mesmo, e quando vc faz isso apos consultar uma entidade que tem relacionamentos lazy e da um get nesse nesse relacionamento vc vai receber essa exception, pois vc fez isso depois que a session que vc usou pra fazer a consulta ja foi fechada.

no blog do hebert ele explica como tratar isso
http://uaihebert.com/?p=1367

jonas.cant

Tentei alterar o fetchType das classes Setor e TipoApartamento para EAGER. Não resolveu o problema. Na classe Apartamento, o relacionamento ManyToOne estaria correto segundo o que eu pude compreender pelo artigo do Hebert. Olhando para os códigos postados acima, o que eu deveria alterar?

jonas.cant

Alguém por favor teria mais alguma ideia de como resolver esse problema? Já pesquisei em trocentos fóruns e não consegui resolver. A maioria fala que seria solucionando colocando o fetchType.EAGER mas pra mim é como se nem tivesse colocado. O erro persiste. Será que não é problema no Dao pelo fato de eu fechar a session toda hora?

darksteel3000

Tipo, pq vc não usa o Cascade? E Deixa que o hibernate faça isso por você? ( Inserção ).

Quanto a busca do combobox, tipo, eu acho que você poderia dar um Hibernate.initialize na coleção ou objeto em questão, ou se você tiver trabalhando com o spring colocar o @Transactional e deixar que ele cuide disso para vc.

jonas.cant

Puts, cara. Não entendi muito bem o que você falou. Desculpe a ignorância.
Primeiro: o que você quer dizer com o Cascade?
Segundo: onde eu colocaria o método Hibernate.initialize?

darksteel3000

Tipo, primeiro vc falou que tava com pro no “Inserir” daí sugeri que você utiilizasse o Cascade nas entidades que deseja inserir junto a entidade pai, pois o hibernate cuida de inserir todas AUTOMAGICAMENTE junto a entidade pai. Daí vc pode utilizar no seu mapeamento o cascade = CascadeType.ALL.

Mas pq utilizar o cascade: Tipo, esse erro se dá pq o hibernate pegou uma sessão pra salvar um objeto e quando ele foi salvar o outro, cabosse a sessão hehe. Ai lascou uhashuaus, colocando o cascade ele salva “TUTO” e depois que finaliza a sessão.

Outra alternativa seria implementar um modelo Open Session in View, onde a sessão ficaria aberta até que todo o seu processamento fosse concluido.

Já o segundo problema é o seguinte, no seu metodo de buscar ai que carrega a lista de paises ou estados, vc poderia mandar o Hibernate inicializar essa coleção de objetos sem a necessidade de utilizar EAGER no mapeamento. Como?

Tipo, vamos supor que no seu metodo de carregar paises ele tem uma coleção de estados que também serão carregados. Vc faria assim:

dentro do teu metodo de listar paises, colocarias antes de sua finalização:

Hibernate.initialize(pais.getEstados());

jonas.cant

Eu acredito que eu não deveria usar o Cascade pelo seguinte motivo: eu não quero que o Setor e o Tipo de Apartamento sejam inseridos juntos no momento de inserir um Apartamento. O Setor e Tipo de Apartamento são cadastros a parte que serão feitos antes de se cadastrar um Apartamento. Na tele de cadastro de Apartamento apenas aparecerá dois combobox listando o setor e o tipo de apartamento. Entende? Se foi o que eu entendi, não faz sentido por isso no meu caso.

E sobre o erro do combobox, no managed bean de países eu tenho um método que carrega os estados conforme país selecionado, e no managed bean de estados eu tenho um método que carrega as cidades conforme estado selecionado.

Esse erro de “no Session” só passou a acontecer depois que eu comecei a fechar a session (session.Close) a cada método de listagem, inserção, alteração ou exclusão. Eu acho que é algum detalhe em relação ao hibernate mas não faço ideia do que possa ser.

darksteel3000

Opa, então é o caso da utilização do que eu ja tinha comentado, o “OPEN SESSION IN VIEW” é muitooooo massa, utilizado pelo Spring.

Olha aqui: http://blog.camilolopes.com.br/tag/open-session-view/

No mais, é um padrão que deixa tua session aberta enquanto ocorre transações na view, depois ela fecha.

É muito simples implementar.

Qualquer coisa só falar !

jonas.cant

Só uma observação: eu utilizo apenas o Spring Security. Não utilizo o Spring MVC.
Frameworks que eu utilizo no momento: JSF + Hibernate + Spring Security e PrimeFaces para a parte visual.

darksteel3000

Sim sim, sem pro pow, esse padrão que te indiquei pode ser implementado só com o hibernate tanto em projetos desktop quanto web.

Olha ai, ja achei pra vc, só adaptar: http://blog.camilolopes.com.br/opensessionviewsolucao/

jonas.cant

Amigão, obrigado. Assim que eu tiver um tempo vou tentar implementar aquela solução. Assim que der certo (ou não) eu voltarei aqui no tópico relatando o resultado.

jonas.cant

Só uma dúvida: implementando aquela solução do blog, eu devo deixar o Session.close() nos métodos de listagem, inserção, alteração e exclusão? Se eu tiver que tirar, em que momento a sessão será fechada?

Criado 13 de março de 2013
Ultima resposta 13 de mar. de 2013
Respostas 12
Participantes 3