Persist and Seam Managed Lifecycle
valtoni Nov 22, 2006 10:31 AMHello!
I´m a newbie, but with some direction.
I´m trying to do persistence with EJB3 injected EntityManager by annotation @PersistenceContext, but appear witch this EntityManager close the session all time that a call is made in page, because after the first call (all good occurs), in the second call, this appear:
"org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.bdh.view.seam.entity.FuncionarioEntity".
I put all code from the registration seam example and the code of EJB appear well simpler then mine.
My ejb:
import static org.jboss.seam.ScopeType.EVENT; import java.util.List; import javax.annotation.Resource; import javax.ejb.Remove; import javax.ejb.SessionContext; import javax.ejb.Stateful; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.hibernate.validator.InvalidValue; import org.jboss.seam.annotations.Destroy; import org.jboss.seam.annotations.Factory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Out; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.datamodel.DataModel; import org.jboss.seam.annotations.datamodel.DataModelSelection; import org.jboss.seam.core.FacesMessages; import org.jboss.seam.log.Log; import br.com.bdh.view.seam.ejb.Funcionario; import br.com.bdh.view.seam.entity.FuncionarioEntity; @Stateful @Scope(EVENT) @Name("cadastrofuncionario") public class FuncionarioBean implements Funcionario { @DataModel private List<FuncionarioEntity> listaFuncionarios; @In(create = true) private FuncionarioEntity funcionario; @Out(required = false) @DataModelSelection private FuncionarioEntity funcionarioDaLista; @PersistenceContext private EntityManager em; @In(create=true) private transient FacesMessages facesMessages; @Logger private Log log; private boolean isExists(FuncionarioEntity funcionario) { return em.createQuery("from FuncionarioEntity f where f.nome = :nome") .setParameter("nome", funcionario.getNome()) .getResultList().size() > 0; } public String criar() { log.info("Tentativa de input de funcionário."); if (em.contains(funcionario)) { facesMessages.add("O funcionário #{funcionario.nome} já está cadastrado"); return null; } else { try { log.info("Funcionário a persistir: " + funcionario); if (isExists(funcionario)) { facesMessages.add("Este funcionário já existe. Não pode ser cadastrado novamente"); } else { //funcionario = em.merge(funcionario); em.persist(funcionario); //em.flush(); log.info("Novo funcionário #{funcionario.nome} cadastrado com sucesso"); facesMessages.add("O funcionário #{funcionario.nome} foi cadastrado com sucesso"); } } catch (org.hibernate.validator.InvalidStateException e) { InvalidValue[] vals = e.getInvalidValues(); String message = "Estados inválidos: "; for (InvalidValue val: vals) { message += "- " + val + "\n"; } facesMessages.add(message); return "/cadastroFuncionario.jsp"; } catch (RuntimeException e) { ctx.setRollbackOnly(); facesMessages.add("Erro: " + e.getMessage()); } return "/cadastroFuncionario.jsp"; } } @Factory("listaFuncionarios") public void findFuncionarios() { listaFuncionarios = em.createQuery("from FuncionarioEntity f order by f.nome desc") .setMaxResults(100) .getResultList(); log.debug("Lista de funcionários obtida: " + listaFuncionarios.size()); } @Destroy @Remove public void destroy() { listaFuncionarios = null; } }
PS.: When i remove the comment of
//funcionario = em.merge(funcionario);it´s works perfectly. But in the examples this was not necessary... I don´t know the reason!!!
PS2.: I try to do @Transient field in entity and when his trying to read field "diasTrabalhados", the error "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.bdh.view.seam.entity.FuncionarioEntity.diasTrabalhados, no session or session was closed" appear.
The code of entity:
import static org.jboss.seam.ScopeType.SESSION; import java.io.Serializable; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table; import javax.persistence.Transient; import org.hibernate.validator.Length; import org.hibernate.validator.NotNull; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @Entity @Name("funcionario") @Scope(SESSION) @Table(name = "FUNCIONARIO") public class FuncionarioEntity implements Serializable { private static final long serialVersionUID = -7360165347366125305L; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name="IDFUNCIONARIO") private int id; @NotNull @Length(min=10, max=100) private String nome; @OneToMany(mappedBy="funcionario") @OrderBy("data desc") private List<DiaUtilEntity> diasTrabalhados; @Transient public int getHorasTrabalhadas() { if (diasTrabalhados == null) { return 0; } else { return diasTrabalhados.size(); } //return 0; } public FuncionarioEntity() { } public FuncionarioEntity(int id, String nome) { this.id = id; this.nome = nome; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public List<DiaUtilEntity> getDiasTrabalhados() { return diasTrabalhados; } public void setDiasTrabalhados(List<DiaUtilEntity> diasTrabalhados) { this.diasTrabalhados = diasTrabalhados; } public String toString() { int noDiasTrabalhados = 0; if (getDiasTrabalhados() != null) { noDiasTrabalhados = getDiasTrabalhados().size(); } return "Id: " + id + " nome: " + nome + " dias trabalhados: " + noDiasTrabalhados; } }