EJB + JPA + PersistenceBag

Boa tarde senhores

Desenvolvo uma ferramenta para cadastro de currículos para a empresa que trabalho. Decidi desenvolvê-la em EJB 3.0, pois além de ser necessário controle de transação, traria as facilidades de injeção de dependências.
Consegui desenvolver alguns cadastros simples utilizando JSF 2.0 e Primefaces.

O problema que tenho uma classe mais complexa com vários PersistenceBag (ElementCollection e ManyToMany) , todos com Lazy mode, e o entityManager sempre está fechado ao tentar buscar os dados deles.

Alguém pode me ajudar?

Isso aqui pode te dar umas ideias

Quatro soluções para LazyInitializationException

[quote=Rodrigo Sasaki]Isso aqui pode te dar umas ideias

Quatro soluções para LazyInitializationException[/quote]

Vou dar uma lida e se eu conseguir ou não eu posto aqui.

Eu li o artigo e entendi os 4 metodos, a questão é, eu não tenho somente um ManyToMany ou ElementCollection.

Abaixo está a estrutura da classe.

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.modelo.endereco.Endereco;
import br.com.acifranca.modelo.usuario.TipoUsuario;
import br.com.acifranca.modelo.usuario.Usuario;
import br.com.acifranca.modelo.vaga.Funcao;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
import org.joda.time.DateTime;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Entity
@Table(schema = "AcifEmpregos")
public class Candidato extends AbstractModelo implements Usuario {

    private static final int NOME_LENGTH = 60;
    private static final int EMAIL_LENGTH = 100;
    private static final int CPF_LENGTH = 11;
    private static final int SENHA_LENGTH = 32;
    private static final int RG_LENGTH = 20;
    private static final int DEFICIENCIA_LENGTH = 100;
    private static final int HABILIDADESQUALIFICACOES_LENGTH = 1024;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(nullable = false, length = NOME_LENGTH)
    private String nome;
    @Embedded
    private Endereco endereco;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date dataNascimento;
    @Enumerated(EnumType.STRING)
    private Sexo sexo;
    @Enumerated(EnumType.STRING)
    private EstadoCivil estadoCivil;
    @Column(length = EMAIL_LENGTH)
    private String email;
    @Column(length = CPF_LENGTH)
    private String cpf;
    @Column(length = SENHA_LENGTH)
    private String senha;
    @Column(length = RG_LENGTH)
    private String rg;
    private boolean possuiDeficiencia;
    @Column(length = DEFICIENCIA_LENGTH)
    private String deficiencia;
    @ElementCollection(targetClass = Cnh.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoCHN")
    @Enumerated(EnumType.STRING)
    private Set<Cnh> cnh;
    @ElementCollection(targetClass = Periodo.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoPeriodo")
    @Enumerated(EnumType.STRING)
    private Set<Periodo> periodo;
    private boolean disponivelViagem;
    private boolean salarioCombinar;
    private double pretensaoSalarial;
    @Column(length = HABILIDADESQUALIFICACOES_LENGTH)
    private String habilidadesQualificacoes;
    @ElementCollection(targetClass = Curso.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoCursos")
    private List<Curso> cursos;
    @OneToMany(mappedBy = "candidato")
    private List<ExperienciaProfissional> experienciaProfissionais;
    @ElementCollection(targetClass = Formacao.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoFormacao")
    private List<Formacao> formacoes;
    @ManyToMany
    @JoinTable(schema = "AcifEmpregos", name = "CandidatoFuncaoInteresse")
    private List<Funcao> funcoesInteresse;
    @ElementCollection(targetClass = Telefone.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoTelefone")
    private List<Telefone> telefones;
    @ElementCollection(targetClass = IdiomaCandidato.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoIdioma")
    private List<IdiomaCandidato> idiomas;

    //gets / sets

Eu até tentei fazer a carga via @PostLoad e colocar em um novo List mas o jpa remove as listas.

  @PostLoad
  public void aposCarregar() {
        cnh = Util.createSet(cnh); //esse util cria um ArrayList com o conteudo do List original
        cursos = Util.createList(cursos);
        experienciaProfissionais = Util.createList(experienciaProfissionais);
        formacoes = Util.createList(formacoes);
        funcoesInteresse = Util.createList(funcoesInteresse);
        idiomas = Util.createList(idiomas);
        periodo = Util.createSet(periodo);
        telefones = Util.createList(telefones);
    }

Ainda não consegui resolver o problema.

Alguém sabe como contornar o problema?

Estou pensando em migrar o sistema para JDBC pois controlo melhor tudo isso. Mas aí fica uma dúvida, cada classe terei que construir um dao?

Bom dia pessoal

ninguém consegue me ajudar nessa não? Não queria ter que remover toda a estrutura do EJB e voltar a usar somente CDI com JDBC.

[quote=tebosoftware]Bom dia pessoal

ninguém consegue me ajudar nessa não? Não queria ter que remover toda a estrutura do EJB e voltar a usar somente CDI com JDBC.[/quote]

Você está usando JTA? Os controles do entitymanager são feitos pelo container?

Sim estou utilizando JTA controlado pelo container. Só que ele fecha antes da view ser renderizada.

Cola aqui as camadas que chamam a entidade (Principalmente pra poder observar o contexto delas.)

Ficou meio longo mas está ai.

Candidato

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.modelo.endereco.Endereco;
import br.com.acifranca.modelo.usuario.TipoUsuario;
import br.com.acifranca.modelo.usuario.Usuario;
import br.com.acifranca.modelo.vaga.Funcao;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
import org.joda.time.DateTime;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Entity
@Table(schema = "AcifEmpregos")
public class Candidato extends AbstractModelo implements Usuario {

    private static final int NOME_LENGTH = 60;
    private static final int EMAIL_LENGTH = 100;
    private static final int CPF_LENGTH = 11;
    private static final int SENHA_LENGTH = 32;
    private static final int RG_LENGTH = 20;
    private static final int DEFICIENCIA_LENGTH = 100;
    private static final int HABILIDADESQUALIFICACOES_LENGTH = 1024;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(nullable = false, length = NOME_LENGTH)
    private String nome;
    @Embedded
    private Endereco endereco;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date dataNascimento;
    @Enumerated(EnumType.STRING)
    private Sexo sexo;
    @Enumerated(EnumType.STRING)
    private EstadoCivil estadoCivil;
    @Column(length = EMAIL_LENGTH)
    private String email;
    @Column(length = CPF_LENGTH)
    private String cpf;
    @Column(length = SENHA_LENGTH)
    private String senha;
    @Column(length = RG_LENGTH)
    private String rg;
    private boolean possuiDeficiencia;
    @Column(length = DEFICIENCIA_LENGTH)
    private String deficiencia;
    @ElementCollection(targetClass = Cnh.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoCHN")
    @Enumerated(EnumType.STRING)
    private Set<Cnh> cnh;
    @ElementCollection(targetClass = Periodo.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoPeriodo")
    @Enumerated(EnumType.STRING)
    private Set<Periodo> periodo;
    private boolean disponivelViagem;
    private boolean salarioCombinar;
    private double pretensaoSalarial;
    @Column(length = HABILIDADESQUALIFICACOES_LENGTH)
    private String habilidadesQualificacoes;
    @ElementCollection(targetClass = Curso.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoCursos")
    private List<Curso> cursos;
    @OneToMany(mappedBy = "candidato")
    private List<ExperienciaProfissional> experienciaProfissionais;
    @ElementCollection(targetClass = Formacao.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoFormacao")
    private List<Formacao> formacoes;
    @ManyToMany
    @JoinTable(schema = "AcifEmpregos", name = "CandidatoFuncaoInteresse")
    private List<Funcao> funcoesInteresse;
    @ElementCollection(targetClass = Telefone.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoTelefone")
    private List<Telefone> telefones;
    @ElementCollection(targetClass = IdiomaCandidato.class, fetch = FetchType.LAZY)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoIdioma")
    private List<IdiomaCandidato> idiomas;

    
}

Cnh

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
public enum Cnh {

    A("A"), B("B"), C("C"), D("D"), E("E");
    private String descricao;

    private Cnh(String descricao) {
        this.descricao = descricao;
    }

    public String getDescricao() {
        return descricao;
    }
}

EstadoCivil

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 25/06/2012
 */
public enum EstadoCivil {

    SOLTEIRO("Solteiro (a)"),
    CASADO("Casado (a)"),
    DIVORCIADO("Divorciado (a)"),
    VIUVO ("Viúvo (a)"),
    UNIAO_ESTAVEL("União Estável");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private EstadoCivil(String descricao) {
        this.descricao = descricao;
    }
}

Grau

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 26/06/2012
 */
public enum Grau {

    FUNDAMENTAL("Fundamental"),
    MEDIO("Médio"),
    TECNICO("Técnico"),
    GRADUACAO("Graduado"),
    POSGRADUADO("Pós-graduado"),
    MESTRADO("Mestrado"),
    DOUTORADO("Doutorado"),
    POSDOUTORADO("Pós-doutorado");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private Grau(String descricao) {
        this.descricao = descricao;
    }
}

Nivel

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 26/06/2012
 */
public enum Nivel {

    BASICO("Básico"),
    INTERMEDIARIO("Intermediário"),
    AVANCADO("Avançado");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private Nivel(String descricao) {
        this.descricao = descricao;
    }
}

Periodo

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 25/06/2012
 */
public enum Periodo {

    MANHA("Manhã"),
    TARDE("Tarde"),
    NOITE("Noite");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private Periodo(String descricao) {
        this.descricao = descricao;
    }
}

Sexo

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 25/06/2012
 */
public enum Sexo {

    MASCULINO("Masculino"),
    FEMININO("Feminino");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private Sexo(String descricao) {
        this.descricao = descricao;
    }
}

TipoTelefone

package br.com.acifranca.modelo.candidato;

/**
 *
 * @author thales @data 25/06/2012
 */
public enum TipoTelefone {

    FIXO("Fixo"),
    CELULAR("Celular"),
    FAX("Fax");
    private String descricao;

    public String getDescricao() {
        return descricao;
    }

    private TipoTelefone(String descricao) {
        this.descricao = descricao;
    }
}

Telefone

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Embeddable
public class Telefone extends AbstractModelo {

    private static final int NUMERO_TAMANHO = 20;
    @Column(nullable = false, length = NUMERO_TAMANHO)
    private String numero;
    @Enumerated(EnumType.STRING)
    private TipoTelefone tipoTelefone;
    
}

IdiomaCandidato

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.modelo.endereco.Estado;
import br.com.acifranca.modelo.vaga.Idioma;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import javax.persistence.*;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Embeddable
public class IdiomaCandidato extends AbstractModelo {

    private static final int INSTITUICAO_LENGTH = 100;
    private static final int CIDADE_LENGTH = 50;
    @ManyToOne(optional = false)
    private Idioma idioma;
    @Enumerated(EnumType.STRING)
    private Nivel nivel;
    private Integer mesInicial;
    private Integer anoInicial;
    private Integer mesFinal;
    private Integer anoFinal;
    private boolean concluido;
    @Column(length = INSTITUICAO_LENGTH, nullable = false)
    private String instituicao;
    @Column(length = CIDADE_LENGTH, nullable = false)
    private String cidade;
    @ManyToOne
    private Estado estado;

}

Formacao

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.modelo.endereco.Estado;
import br.com.acifranca.modelo.vaga.Area;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import javax.persistence.*;

/**
 *
 * @author thales
 * @data 26/06/2012
 */
@Embeddable
public class Formacao extends AbstractModelo {

    private static final int DESCRICAO_LENGTH = 100;
    private static final int INSTITUICAO_LENGTH = 100;
    private static final int CIDADE_LENGTH = 50;
    @Column(length = DESCRICAO_LENGTH, nullable = false)
    private String descricao;
    private Integer mesInicial;
    private Integer anoInicial;
    private Integer mesFinal;
    private Integer anoFinal;
    private boolean concluido;
    @Column(length = INSTITUICAO_LENGTH, nullable = false)
    private String instituicao;
    @Column(length = CIDADE_LENGTH, nullable = false)
    private String cidade;
    @ManyToOne
    private Estado estado;
    @Enumerated(EnumType.STRING)
    private Grau grau;
    @ManyToOne
    private Area area;
}

ExperienciaProfissional

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.modelo.endereco.Endereco;
import br.com.acifranca.modelo.vaga.Area;
import br.com.acifranca.modelo.vaga.Cargo;
import br.com.acifranca.modelo.vaga.Funcao;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Entity
@Table(schema = "AcifEmpregos", name = "CandidatoExpProf")
public class ExperienciaProfissional extends AbstractModelo {

    private static final int EMPRESA_LENGTH = 60;
    private static final int RESPONSAVEL_LENGTH = 60;
    private static final int DESCRICAO_FUNCOES_LENGTH = 1024;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @ManyToOne
    private Candidato candidato;
    @Column(nullable = false, length = EMPRESA_LENGTH)
    private String empresa;
    @Column(nullable = false, length = RESPONSAVEL_LENGTH)
    private String responsavel;
    @Embedded
    private Endereco endereco;
    private Integer mesInicial;
    private Integer anoInicial;
    private Integer mesFinal;
    private Integer anoFinal;
    private boolean empregoAtual;
    @Column(nullable = false, length = DESCRICAO_FUNCOES_LENGTH)
    private String descricaoFuncoes;
    @ManyToOne(cascade = CascadeType.ALL, optional = false)
    private Area area;
    @ManyToMany
    @JoinTable(schema = "AcifEmpregos", name = "CandidatoExpProfFuncao")
    private List<Funcao> funcao;
    @ManyToOne(cascade = CascadeType.ALL, optional = false)
    private Cargo cargo;
    @ElementCollection(targetClass = Telefone.class)
    @CollectionTable(schema = "AcifEmpregos", name = "CandidatoExpProfTelefone")
    private List<Telefone> telefones;

}

Curso

package br.com.acifranca.modelo.candidato;

import br.com.acifranca.modelo.AbstractModelo;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import javax.persistence.*;

/**
 *
 * @author thales
 * @data 25/06/2012
 */
@Embeddable
public class Curso extends AbstractModelo {

    private static final int DESCRICAO_LENGTH = 60;
    @Column(nullable = false, length = DESCRICAO_LENGTH)
    private String descricao;
    private Integer mesInicial;
    private Integer anoInicial;
    private Integer mesFinal;
    private Integer anoFinal;
    private Integer cargaHoraria;
    private boolean concluido;
}

CandidatoDAO

package br.com.acifranca.dao.candidato;

import br.com.acifranca.dao.DAO;
import br.com.acifranca.dao.DAOException;
import br.com.acifranca.modelo.candidato.Candidato;
import java.util.List;
import javax.ejb.Local;

/**
 *
 * @author Shubacca
 * @data 03/10/2012
 */
@Local
public interface CandidatoDAO extends DAO<Candidato> {

    public Candidato buscarPorCpf(String cpf) throws DAOException;

    public List<Candidato> listarPorNome(String nome) throws DAOException;

    public Candidato buscarPorIdentificacao(String cpf, String senha) throws DAOException;
}

CandidatoDAOImpl

package br.com.acifranca.dao.candidato;

import br.com.acifranca.dao.AbstractDAO;
import br.com.acifranca.dao.DAOException;
import br.com.acifranca.modelo.candidato.Candidato;
import br.com.acifranca.util.Util;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;

/**
 *
 * @author Shubacca
 * @data 03/10/2012
 */
@Stateless
@SuppressWarnings(value = "unchecked")
public class CandidatoDAOImpl extends AbstractDAO<Candidato> implements CandidatoDAO {

    public CandidatoDAOImpl() {
        super(Candidato.class);
    }

    @Override
    public Candidato buscarPorCpf(String cpf) throws DAOException {
        try {
            return executeQuerySingleResult("from Candidato where cpf = :cpf",
                    "cpf", cpf);
        } catch (Throwable ex) {
            throw new DAOException("Falha ao buscar por cpf", ex);
        }
    }

    @Override
    public List<Candidato> listarPorNome(String nome) throws DAOException {
        try {
            return executeQuery("from Candidato where nome like :nome order by nome",
                    "nome", Util.prepararParametro(nome));
        } catch (Throwable ex) {
            throw new DAOException("Falha ao buscar por cpf", ex);
        }
    }

    @Override
    public Candidato buscarPorIdentificacao(String cpf, String senha) throws DAOException {
        try {
            Map<String, Object> parametros = Util.createMap();
            parametros.put("cpf", cpf);
            parametros.put("senha", senha);
            return executeQuerySingleResult("from Candidato "
                    + "where cpf = :cpf and "
                    + "senha = :senha",
                    parametros);
        } catch (Throwable ex) {
            throw new DAOException("Falha ao buscar por Identificação", ex);
        }
    }
}

CandidatoController

package br.com.acifranca.controller.candidato;

import br.com.acifranca.controller.Controller;
import br.com.acifranca.modelo.candidato.Candidato;
import javax.ejb.Local;

/**
 *
 * @author Shubacca
 * @data 03/10/2012
 */
@Local
public interface CandidatoController extends Controller<Candidato> {

    public void setCpf(String cpf);

    public String getCpf();

    public void setNome(String nome);

    public String getNome();

    public void setTipoBusca(TipoBusca tipoBusca);

    public TipoBusca getTipoBusca();
    
    public Candidato buscarPorCpf(String cpf);
    
    public static enum TipoBusca {

        CPF("Cpf"), NOME("Nome");
        private String descricao;

        private TipoBusca(String descricao) {
            this.descricao = descricao;
        }

        public String getDescricao() {
            return descricao;
        }
    }
}

CandidatoControllerImpl

package br.com.acifranca.controller.candidato;

import br.com.acifranca.controller.AbstractController;
import br.com.acifranca.dao.DAOException;
import br.com.acifranca.dao.candidato.CandidatoDAO;
import br.com.acifranca.modelo.candidato.Candidato;
import br.com.acifranca.util.Util;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;

/**
 *
 * @author Shubacca
 * @data 03/10/2012
 */
@Stateless
public class CandidatoControllerImpl extends AbstractController<Candidato, CandidatoDAO> implements CandidatoController {

    @EJB
    private CandidatoDAO candidatoDAO;
    private String cpf;
    private String nome;
    private TipoBusca tipoBusca;

    public CandidatoControllerImpl() {
        super(Candidato.class, CandidatoDAO.class);
    }

    @Override
    protected void limparParametros() {
        cpf = null;
        nome = null;
        tipoBusca = TipoBusca.NOME;
    }

    @Override
    protected CandidatoDAO getDao() {
        return candidatoDAO;
    }

    @Override
    protected List<Candidato> listar() throws DAOException {
        switch (tipoBusca) {
            case CPF: {
                List<Candidato> retorno = Util.createList();
                Candidato c = getDao().buscarPorCpf(cpf);
                if (c != null) {
                    retorno.add(c);
                }
                return retorno;
            }
            case NOME: {
                return getDao().listarPorNome(nome);
            }
        }
        return null;
    }

    @Override
    public void setCpf(String cpf) {
        this.cpf = cpf;
    }

    @Override
    public String getCpf() {
        return cpf;
    }

    @Override
    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String getNome() {
        return nome;
    }

    @Override
    public TipoBusca getTipoBusca() {
        return tipoBusca;
    }

    @Override
    public void setTipoBusca(TipoBusca tipoBusca) {
        this.tipoBusca = tipoBusca;
    }

    @Override
    public Candidato buscarPorCpf(String cpf) {
        try {
            return candidatoDAO.buscarPorCpf(cpf);
        } catch (DAOException ex) {
            Logger.getLogger(CandidatoControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
}

CandidatoBean

package br.com.acifranca.web.candidato;

import br.com.acifranca.controller.candidato.CandidatoController;
import br.com.acifranca.controller.candidato.CandidatoController.TipoBusca;
import br.com.acifranca.dao.DAOException;
import br.com.acifranca.dao.endereco.EnderecoGeralDAO;
import br.com.acifranca.dao.endereco.EstadoDAO;
import br.com.acifranca.dao.vaga.FuncaoDAO;
import br.com.acifranca.modelo.candidato.Candidato;
import br.com.acifranca.modelo.candidato.Curso;
import br.com.acifranca.modelo.candidato.ExperienciaProfissional;
import br.com.acifranca.modelo.candidato.Formacao;
import br.com.acifranca.modelo.candidato.IdiomaCandidato;
import br.com.acifranca.modelo.candidato.Telefone;
import br.com.acifranca.modelo.endereco.EnderecoGeral;
import br.com.acifranca.modelo.vaga.Area;
import br.com.acifranca.modelo.vaga.Funcao;
import br.com.acifranca.util.JSFUtil;
import br.com.acifranca.util.Util;
import br.com.acifranca.web.AbstractBean;
import br.com.acifranca.web.email.EmailAPI;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

/**
 *
 * @author Shubacca
 * @data 03/10/2012
 */
@ManagedBean
public class CandidatoBean extends AbstractBean<Candidato, CandidatoController> {

    @EJB
    private CandidatoController candidatoController;
    @EJB
    private EnderecoGeralDAO enderecoGeralDAO;
    @EJB
    private EstadoDAO estadoDAO;
    @EJB
    private FuncaoDAO funcaoDAO;
    private String cpf;
    private String nome;
    private CandidatoController.TipoBusca tipoBusca = CandidatoController.TipoBusca.NOME;
    private List<EnderecoGeral> listaEnderecoGeral;
    private List<SelectItem> tipoBuscas;
    private Area areaFiltro;
    private List<Funcao> listaFuncoes;
    private String descricaoFuncaoFiltro;
    private boolean novoCandidato = false;

    public CandidatoBean() {
        super(Candidato.class, CandidatoController.class);
    }

    public List<SelectItem> getTipoBuscas() {
        if (tipoBuscas == null) {
            tipoBuscas = Util.createList();
            for (CandidatoController.TipoBusca tb : CandidatoController.TipoBusca.values()) {
                tipoBuscas.add(new SelectItem(tb, tb.getDescricao()));
            }
        }
        return tipoBuscas;
    }

    @Override
    protected CandidatoController getController() {
        return candidatoController;
    }

    public String getCpf() {
        return cpf;
    }

    public void setCpf(String cpf) {
        this.cpf = cpf;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public TipoBusca getTipoBusca() {
        return tipoBusca;
    }

    public void setTipoBusca(TipoBusca tipoBusca) {
        this.tipoBusca = tipoBusca;
    }

    public void onCepChange(ValueChangeEvent event) {
        if (!Util.isEqual(event.getOldValue(), event.getNewValue()) && !Util.isNull(event.getNewValue())) {
            try {
                listaEnderecoGeral = enderecoGeralDAO.listarPorCep(((String) event.getNewValue()).replaceAll("\\D", ""));
                if (!listaEnderecoGeral.isEmpty()) {
                    if (listaEnderecoGeral.size() == 1) {
                        EnderecoGeral eg = listaEnderecoGeral.get(0);
                        if (!Util.isEqual(getModelo().getEndereco().getSeqEnderecoGeral(), eg.getSeq())) {
                            preencheEndereco(eg);
                        }
                    } else {
                        JSFUtil.addCallbackParam("mostrarDialogoEndereco", true);
                    }
                } else {
                    getModelo().getEndereco().setSeqEnderecoGeral(null);
                }
            } catch (DAOException ex) {
                Logger.getLogger(CandidatoBean.class.getName()).log(Level.SEVERE, null, ex);
                JSFUtil.adicionarErro("Falha ao buscar cep", ex);
            }
        }
    }

    public void preencheEndereco(EnderecoGeral eg) {
        try {
            getModelo().getEndereco().setLogradouro(eg.getLogradouro());
            getModelo().getEndereco().setBairro(eg.getBairro());
            getModelo().getEndereco().setCidade(eg.getCidade());
            getModelo().getEndereco().setEstado(estadoDAO.buscar(eg.getUf()));
            getModelo().getEndereco().setCep(eg.getCep());
            getModelo().getEndereco().setSeqEnderecoGeral(eg.getSeq());
        } catch (DAOException ex) {
            Logger.getLogger(CandidatoBean.class.getName()).log(Level.SEVERE, null, ex);
            JSFUtil.adicionarErro("Falha ao buscar estado", ex);
        }
    }

    public List<EnderecoGeral> getListaEnderecoGeral() {
        if (listaEnderecoGeral == null) {
            listaEnderecoGeral = Util.createList();
        }
        return listaEnderecoGeral;
    }

    public void adicionarTelefone() {
        if (getStatus() != Status.NAVEGANDO) {
            getModelo().getTelefones().add(new Telefone());
        }
    }

    public void removerTelefone(Telefone telefone) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getTelefones().contains(telefone)) {
            getModelo().getTelefones().remove(telefone);
        }
    }

    public void adicionarIdioma() {
        if (getStatus() != Status.NAVEGANDO) {
            getModelo().getIdiomas().add(new IdiomaCandidato());
        }
    }

    public void removerIdioma(IdiomaCandidato idioma) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getIdiomas().contains(idioma)) {
            getModelo().getIdiomas().remove(idioma);
        }
    }

    public void adicionarCurso() {
        if (getStatus() != Status.NAVEGANDO) {
            getModelo().getCursos().add(new Curso());
        }
    }

    public void removerCurso(Curso curso) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getCursos().contains(curso)) {
            getModelo().getCursos().remove(curso);
        }
    }

    public void adicionarFormacao() {
        if (getStatus() != Status.NAVEGANDO) {
            getModelo().getFormacoes().add(new Formacao());
        }
    }

    public void removerFormacao(Formacao formacao) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getFormacoes().contains(formacao)) {
            getModelo().getFormacoes().remove(formacao);
        }
    }

    public void adicionarExperienciaProfissional() {
        if (getStatus() != Status.NAVEGANDO) {
            getModelo().getExperienciaProfissionais().add(new ExperienciaProfissional(getModelo()));
        }
    }

    public void removerExperienciaProfissional(ExperienciaProfissional experienciaProfissionais) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getExperienciaProfissionais().contains(experienciaProfissionais)) {
            getModelo().getExperienciaProfissionais().remove(experienciaProfissionais);
        }
    }

    public void adicionarTelefoneExpProf(ExperienciaProfissional experienciaProfissionais) {
        experienciaProfissionais.getTelefones().add(new Telefone());
    }

    public void removerTelefoneExpProf(ExperienciaProfissional experienciaProfissionais, Telefone telefone) {
        if (experienciaProfissionais.getTelefones().contains(telefone)) {
            experienciaProfissionais.getTelefones().remove(telefone);
        }
    }

    public void adicionarFuncao(Funcao funcao) {
        if (getStatus() != Status.NAVEGANDO && !getModelo().getFuncoesInteresse().contains(funcao)) {
            getModelo().getFuncoesInteresse().add(funcao);
        }
    }

    public void removerFuncao(Funcao funcao) {
        if (getStatus() != Status.NAVEGANDO && getModelo().getFuncoesInteresse().contains(funcao)) {
            getModelo().getFuncoesInteresse().remove(funcao);
        }
    }

    public Area getAreaFiltro() {
        return areaFiltro;
    }

    public void setAreaFiltro(Area areaFiltro) {
        this.areaFiltro = areaFiltro;
        listaFuncoes = null;
    }

    public List<Funcao> getListaFuncoes() {
        if (listaFuncoes == null) {
            try {
                if (areaFiltro == null) {
                    listaFuncoes = funcaoDAO.listarPorDescricao(descricaoFuncaoFiltro);
                } else {
                    listaFuncoes = funcaoDAO.listarPorDescricao(areaFiltro, descricaoFuncaoFiltro);
                }
            } catch (DAOException ex) {
                Logger.getLogger(CandidatoBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return listaFuncoes;
    }

    public String getDescricaoFuncaoFiltro() {
        return descricaoFuncaoFiltro;
    }

    public void setDescricaoFuncaoFiltro(String descricaoFuncaoFiltro) {
        this.descricaoFuncaoFiltro = descricaoFuncaoFiltro;
        listaFuncoes = null;
    }

    public boolean isNovoCandidato() {
        return novoCandidato;
    }

    public void setNovoCandidato(boolean novoCandidato) {
        this.novoCandidato = novoCandidato;
    }

    public void onCpfChange(ValueChangeEvent event) {
        if (!Util.isEqual(event.getOldValue(), event.getNewValue()) && !Util.isNull(event.getNewValue())) {
            try {
                String _cpf = ((String) event.getNewValue()).replaceAll("\\D", "");
                Candidato c = candidatoController.buscarPorCpf(_cpf);
                if (c != null) {
                    setModelo(c);
                    alterar();
                    JSFUtil.adicionarAlerta("Este cpf já havia sido cadastrado para o candidato abaixo");
                }
            } catch (Throwable ex) {
                Logger.getLogger(CandidatoBean.class.getName()).log(Level.SEVERE, null, ex);
                JSFUtil.adicionarErro("Falha ao buscar cpf", ex);
            }
        }
    }
    private String senha = null;
    private Status _status = null;
    private Candidato _candidato;

    @Override
    public void antesGravar() {
        _status = getStatus();
        _candidato = getModelo();
        if (getStatus() == Status.NOVO) {
            senha = Util.gerarSenha();
            getModelo().setSenha(senha);
        }
    }

    @Override
    protected void depoisGravar() {
        if (_status == Status.NOVO) {
            EmailAPI.enviarEmail(_candidato.getEmail(), "Senha de acesso",
                    "<p>Seja bem vindo " + _candidato.getNome() + "</p>"
                    + "<p>O seu usuário de acesso é o seu Cpf: " + _candidato.getCpf() + "</p>"
                    + "<p>e sua senha é: " + senha + "</p>"
                    + "<p>Sua senha poderá ser alterada após acessar o site.</p>");
        }
    }
}

Esse ManagedBean não tem Escopo/Contexto? Porque pense comigo, se você utilizar RequestScoped, ele irá injetar TUDO(novo) cada vez que existir um request. Tente utilizar ViewScoped no seu ManagedBean e ve se funciona.

Ele está viewscoped sim, é que vem da herança

AbstractBean

package br.com.acifranca.web;

import br.com.acifranca.controller.Controller;
import br.com.acifranca.controller.ControllerException;
import br.com.acifranca.modelo.Modelo;
import br.com.acifranca.util.JSFUtil;
import br.com.acifranca.util.Util;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ViewScoped;

/**
 *
 * @author Shubacca
 * @data 01/10/2012
 */
@SuppressWarnings(value = "unchecked")
@ViewScoped
public abstract class AbstractBean&lt;M extends Modelo, C extends Controller&gt;&lt;M&gt;&gt; implements Serializable {

    private Class&lt;M&gt; modeloClass;
    private Class&lt;C&gt; controllerClass;
    private List&lt;M&gt; lista;
    private M modelo;
    private Status status = Status.NAVEGANDO;

    public AbstractBean(Class&lt;M&gt; modeloClass, Class&lt;C&gt; controllerClass) {
        this.modeloClass = modeloClass;
        this.controllerClass = controllerClass;
    }

   //metodos
}

Por acaso a herança de anotações não funciona? Pois em cadastros simples está tão perfeito

O seu entityManager tem PersistenceContext EXTENDED? Para que o entityManager fique aberto durante todo o ciclo de vida é necessário que o contexto de persistência seja estendido, pelo problema que está descrevendo seu entityManager está com Escopo menor que o seu Bean (Controller)

Bom dia FelipeNevola

Tudo bem eu até entendi que deveria ser colocado como EXTENDED, mas isso implica em ficar StateFul e dessa maneira iria aumentar a carga do servidor não?

Para tentar contornar isso, vou criar só uma classe stateful, vou criar uma classe conexao e nela vou manter o entitymanager. Seria isso?

Conexao .java

package br.com.acifranca.conexao;

import java.io.Serializable;
import javax.ejb.Local;
import javax.persistence.EntityManager;

/**
 *
 * @author Shubacca
 * @data 22/10/2012
 */
@Local
public interface Conexao extends Serializable {

    public EntityManager getEntityManager();
}

ConexaoImpl.java

package br.com.acifranca.conexao;

import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

/**
 *
 * @author Shubacca
 * @data 22/10/2012
 */
@Stateful
public class ConexaoImpl implements Conexao {

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    @Override
    public EntityManager getEntityManager() {
        return entityManager;
    }
}

Errado.

Se você deseja manter o estado entre requisições use Stateful (isto não vai pesar o servidor) e aí o entity manager extended será gerenciado de forma adequada.

Em termos da renderização até funcionou, mas ao tentar acessar as listas pela tela ao tentar adicionar um novo elemento voltou a dar o org.hibernate.LazyInitializationException: could not initialize proxy - no Session.

Eu até tentei fazer assim:

    @PostLoad
    @PostUpdate
    public void aposCarregar() {
        cnh = Util.createSet(cnh);
        cursos = Util.createList(cursos);
        experienciaProfissionais = Util.createList(experienciaProfissionais);
        formacoes = Util.createList(formacoes);
        funcoesInteresse = Util.createList(funcoesInteresse);
        idiomas = Util.createList(idiomas);
        periodo = Util.createSet(periodo);
        telefones = Util.createList(telefones);
    }

Mas quando fui debugar ainda estava o persistencebag lá.