Listar um objeto relacionado a outro com hibernate

6 respostas
kvnallen

Pessoal, como o titulo ja diz tudo, estou tentando listar o fornecedor do meu produto, sendo que ele fica dando o seguinte erro:

failed to lazily initialize a collection of role: modelo.Produto.fornecedores, no session or session was closed

Aqui está minha classe produto:

@Entity
@Table(name = "tbl_produto")
public class Produto {

	@Id
	@GeneratedValue
	@Column(name = "id_produto")
	private long id;

	@Column(name = "nome", nullable = false, length = 50)
	private String nome;

	@Column(name = "preco_unitario", length = 10, nullable = false)
	private double precoUnitario;

	@Column(name = "preco_venda", length = 10, nullable = false)
	private double precoVenda;

	@Column(name = "unidade_medida", length = 10, nullable=false)
	private String unidadeMedida;

	@Column(name = "quantidade_disponivel", length = 20, nullable=false)
	private int quantidadeDisponivel;

	@Column(name = "tipo", length=20)
	private String tipo;

	@ManyToMany(mappedBy="produtos")
	private List<Fornecedor> fornecedores;

Fornecedor:

@Entity
@Table(name = "tbl_fornecedor")
public class Fornecedor {

	@Id
	@GeneratedValue
	@Column(name = "id_fornecedor")
	private long id;

	@Column(name = "nome", nullable = false, unique = true, length = 50)
	private String nome;

	@Column(name = "telefone", length = 20)
	private String telefone;

	@Column(name = "endereco", length = 70)
	private String endereco;

	@Column(name = "numero", length = 6)
	private String numero;

	@Column(name = "bairro", length = 20)
	private String bairro;

	@Column(name = "conta", length = 30)
	private String conta;

	@Column(name = "banco", length = 30)
	private String banco;

	@Column(name = "cnpj", length = 14, unique = true)
	private String cnpj;

	@Column(name = "email", length = 40)
	private String email;
	
	@ManyToMany(fetch=FetchType.LAZY)
	@JoinTable(name="fornecedores_produtos",
	joinColumns = {@JoinColumn(name="id_fornecedor")},
	inverseJoinColumns = {@JoinColumn(name="id_produto")})
	@Cascade(CascadeType.REMOVE)
	private List<Produto> produtos;

Assim estou tentando listar

List<Produto> produtos = new ArrayList<Produto>();
		produtos.addAll(fachada.listarProdutos());
		
		for (int i = 0 ; i < produtos.size(); i++) {
			
			System.out.println(produtos.get(i).getFornecedores().get(i).getNome());
			
		}

6 Respostas

lele_vader

Esse erro está acontecendo porque você colocou a coleção como lazy.

Daí após você passar pelo seu objeto dao você fechou a conexão e quando você faz o

produtos.get(i).getFornecedores() o hibernate tenta puxar a lista de fornecedores e como está fechada a conexão dá esse erro.

LazyInitializationException.

Você pode usar o padrão OpenSessionInView que irá fechar a sessão em um outro momento.

Tem uma página do jboss falando da implementação de OpenSessionInView através de filter

no blog da caellum falando sobre esse assunto também.

http://www.google.com.br/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CF0QFjAA&url=http%3A%2F%2Fblog.caelum.com.br%2Fenfrentando-a-lazyinitializationexception-no-hibernate%2F&ei=kYzHT-KsG4uk8gTg2amDDw&usg=AFQjCNHiFUQ7ULwmiwwqrX3XuPL5O7bFtQ

Nessa página também tem algumas soluções para o problema.

http://uaihebert.com/?p=1367

kvnallen

Se eu trocasse pra EAGER resolvia certo? Mas sempre que eu desse um produto.get(i).getNome(); ele viria com todos os dados do fornecedor né?

Rodrigo_Sasaki

Sim, funciona. Se você trocar seu FetchType para EAGER, você vai ter a coleção carregada sempre que buscar um Produto.
Outro jeito de inicializar é usar métodos estáticos como o Hibernate.initialize(), mas isso tem que ser analisado caso a caso.

lele_vader

O problema do EAGER é que como o digaoneves disse sempre que você consultar por produto ele vai trazer toda a coleção de fornecedores associados.

Então imagina uma consulta que traz 100 produtos e cada um desses 100 tem 100 fornecedores.

kvnallen

Entendo, estou lendo o tutorial mas sou meio noob nessas coisas… No meu caso estou exibindo essas informações em uma JSP, nesse tutorial tem uma classe modelo aqui e tal, preciso criar essa classe e chamar algum método dela para fazer esse OSV ?

lele_vader

Na implementação que eu vi do OSV foi criada um filtro que fecharia a sessão após a exibição da entidade que tem a colecao se não me engano.

Dá uma olhada no tópico da caellum e no site que te passei para ver se você consegue ver um exemplo de implementação ou outra forma de resolver o problema.

Criado 31 de maio de 2012
Ultima resposta 31 de mai. de 2012
Respostas 6
Participantes 3