3
respostas

LazyInicializationException

Pessoal, estou recebendo essa exceção ao tentar usar a lista de e-mails do usuário na lista abaixo:

Obs.: Com fetch EAGER, funciona corretamente, mas são várias listas dentro do objeto.

<p:dataTable value="#{loginBean.responsavel.emails}" var="email" id="tabelaEmails" emptyMessage="Nenhum email">
    <p:column>
        <h:outputText value="#{email.endereco}" />
    </p:column>                        
</p:dataTable>
package br.com.solucao.scf.bean;

import java.io.Serializable;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import br.com.solucao.comum.classesAbstratas.ViewSCF;
import br.com.solucao.comum.navegacao.NavegacaoBean;
import br.com.solucao.scf.modelo.Responsavel;
import br.com.solucao.util.Constantes;

@Named
@ViewScoped
public class LoginBean extends ViewSCF implements Serializable 
{
    private static final long serialVersionUID = 6733716691027056698L;

    private Responsavel responsavel = new Responsavel();

    @Inject
    ResponsavelService service;

    @Inject
    FacesContext context;

    public LoginBean()
    {        
    }

    @PostConstruct
    void init() 
    {
        responsavel.setBundle(ResourceBundle.getBundle(Constantes.CAMINHO_MENSAGENS, FacesContext.getCurrentInstance().getExternalContext().getRequestLocale()));
    }

    public Responsavel getResponsavel() 
    {
        return responsavel;
    }

    public void setResponsavel(Responsavel responsavel) 
    {
        this.responsavel = responsavel;
    }

    public String efetuaLogin() 
    {
        if(service.existe(this.responsavel)) 
        {
            this.responsavel = service.buscaPorId(1);

            context.getExternalContext().getSessionMap().put("responsavel", this.responsavel);
            return NavegacaoBean.paraMenuPrincipal();
        }

        context.getExternalContext().getFlash().setKeepMessages(true);
        context.addMessage("msgLogin", new FacesMessage(responsavel.getBundle().getString("MSG_SENHA_INVALIDA")));

        return NavegacaoBean.paraLogin(); 
    }

    public String efetuaLogout() 
    {
        context.getExternalContext().getSessionMap().remove("responsavel");
        return NavegacaoBean.paraLogin();
    }

}
3 respostas

Oi Rafael, tudo bem?

O problema é o comportamento Lazy do objeto que vc esta trazendo junto com o objeto Responsavel, provavelmente uma lista do objeto Email.

Tem duas formas de solucionar, a primeira, como vc mesmo disse é colocando o eager no relacionamento, porém isso sempre fará várias consultas no banco e toda vez que vc pedir por um responsável ele carregará todos os emails o que consome um recurso importante do banco.

Outra forma é na sua camada de acessoa a Dados, onde vc está buscando por Responsável, fazer um método que retorne reponsavel com email em uma query planejada, mais ou menos assim:

public List<Responsavel> lista(){
    return manager.createQuery("select r from Responsavel r"    
    + " join fetch r.emails", Responsavel.class).getResultList();
}

@Samir Não teria como deixar "automático"?

Pelos exemplos do curso de JSF, tudo flui aparentemente sem ter que fazer esse método, como por exemplo, quando são listados os autores do livro ao editar.

Para deixar no automático só com o fetch.Eager na anotação do relacionamento, mas lembrando que toda vez que o objeto fosse selecionado no banco ele irá puxar todos os Emails relacionados.