Could not initialize proxy - no Session

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.

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

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?

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?

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.

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?

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());

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.

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 !

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.

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/

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.

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?