3
respostas

detached entity passed to persist

Na segunda ação de gravar ocorre erro.

<fieldset>
            <legend>Dados do Autor</legend>
                <h:outputLabel value="Selecione o Autor: " for="autor"/>
                <h:selectOneMenu value="#{livroBean.autorId}">
                    <f:selectItems value="#{livroBean.autores}" var="autor" itemLabel="#{autor.nome}" itemValue="#{autor.id}"/> <!--  recebe o id do autor para poder gravar depois em banco -->
                </h:selectOneMenu>
                <h:commandButton value="Gravar Autor" action="#{livroBean.gravarAutor}"/>
                <h:dataTable value="#{livroBean.autoresDoLivro}" var="autor"><!-- lista  os autores da lista Livro-->
                    <h:column>
                        <h:outputText value="#{autor.nome}"/>
                    </h:column>
                </h:dataTable>
        </fieldset>
Context Path:/livraria
Servlet Path:/livro.xhtml
Path Info:null
Query String:null
Stack Trace
javax.servlet.ServletException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.caelum.livraria.modelo.Livro
javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70)
io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:261)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:248)
io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:77)
io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:167)
io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:761)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)
3 respostas

Olá Aline,

Pode postar aqui os códigos do seu dao de Livro e também o LivroBean, por favor? Assim a gente tem um pouco mais de informação para te ajudar.

sim.. segue, obg pela ajuda!

package br.com.caelum.livraria.dao;

import java.util.List;

import javax.ejb.TransactionAttribute;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaQuery;

public class DAO<T> {

    private final Class<T> classe;

    public DAO(Class<T> classe) {
        this.classe = classe;
    }


    public void adiciona(T t) {

        // consegue a entity manager
        EntityManager em = new JPAUtil().getEntityManager();

        // abre transacao
        em.getTransaction().begin();

        // persiste o objeto
        em.persist(t);

        // commita a transacao
        em.getTransaction().commit();

        // fecha a entity manager
        em.close();
    }

    public void remove(T t) {
        EntityManager em = new JPAUtil().getEntityManager();
        em.getTransaction().begin();

        em.remove(em.merge(t));

        em.getTransaction().commit();
        em.close();
    }

    public void atualiza(T t) {
        EntityManager em = new JPAUtil().getEntityManager();
        em.getTransaction().begin();

        em.merge(t);

        em.getTransaction().commit();
        em.close();
    }

    public List<T> listaTodos() {
        EntityManager em = new JPAUtil().getEntityManager();
        CriteriaQuery<T> query = em.getCriteriaBuilder().createQuery(classe);
        query.select(query.from(classe));

        List<T> lista = em.createQuery(query).getResultList();

        em.close();
        return lista;
    }

    public T buscaPorId(Integer id) {
        EntityManager em = new JPAUtil().getEntityManager();
        T instancia = em.find(classe, id);
        em.close();
        return instancia;
    }

    public int contaTodos() {
        EntityManager em = new JPAUtil().getEntityManager();
        long result = (Long) em.createQuery("select count(n) from livro n")
                .getSingleResult();
        em.close();

        return (int) result;
    }

    public List<T> listaTodosPaginada(int firstResult, int maxResults) {
        EntityManager em = new JPAUtil().getEntityManager();
        CriteriaQuery<T> query = em.getCriteriaBuilder().createQuery(classe);
        query.select(query.from(classe));

        List<T> lista = em.createQuery(query).setFirstResult(firstResult)
                .setMaxResults(maxResults).getResultList();

        em.close();
        return lista;
    }

}
package br.com.caelum.livraria.bean;

import java.util.List;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;

import br.com.caelum.livraria.dao.DAO;
import br.com.caelum.livraria.modelo.Autor;
import br.com.caelum.livraria.modelo.Livro;

@ManagedBean
//@RequestScoped = padrao para manter o Bean por Request
@ViewScoped //A instância de LivroBean existirá enquanto a tela existir.
public class LivroBean {

    private Livro livro = new Livro();
    private Integer autorId;


    public Integer getAutorId() {
        return autorId;
    }

    public void setAutorId(Integer autorId) {
        this.autorId = autorId;
    }

    public Livro getLivro() {
        return livro;
    }

    public List<Autor> getAutores(){
        return new DAO<Autor>(Autor.class).listaTodos();
    }

    //@Transactional(value=TxType.REQUIRES_NEW)

    public void gravar() {
        System.out.println("Gravando livro " + this.livro.getTitulo());

        if (livro.getAutores().isEmpty()) {
            //throw new RuntimeException("Livro deve ter pelo menos um Autor.");
            FacesContext.getCurrentInstance().addMessage("autor", new FacesMessage("Livro deve ter um Autor"));//id do xml do component
            return;
        }

        new DAO<Livro>(Livro.class).adiciona(this.livro);
    }

    public void gravarAutor() {
        Autor autor = new DAO<Autor>(Autor.class).buscaPorId(autorId);//autor selecionado na combo box
        this.livro.adicionaAutor(autor);
    }

    public List<Autor> getAutoresDoLivro(){
        return this.livro.getAutores();
    }

    public List<Livro> getLivros(){
        return new DAO<Livro>(Livro.class).listaTodos();
    }

    //FacesContext = view processada no momento
    //UIComponent = component q esta sendo validado
    //Object = valor digitado pelo usuario
    public void comecaComDigitoUm(FacesContext fc, UIComponent component, Object value) throws  ValidatorException {
        String valor = value.toString();
        if(!valor.startsWith("1")) {
            throw new ValidatorException(new FacesMessage("Deveria comecar com 1"));
        }
    }

}

Olá Aline,

O que está acontecendo é que depois de gravar o primeiro livro, o bean está mantendo o atributo livro que foi salvo e este livro já possui um id (pois acabou de ser gravado no banco). Quando você pede para ele gravar uma segunda vez, o entity manager vai perceber que o objeto já tem id e aí vai considerar que a entidade está no estado detached (possui id mas não está no persistence context).

Para resolver o problema, acredito que basta instanciar um novo livro ao final do método gravar:

    public void gravar() {
        System.out.println("Gravando livro " + this.livro.getTitulo());

        if (livro.getAutores().isEmpty()) {
            //throw new RuntimeException("Livro deve ter pelo menos um Autor.");
            FacesContext.getCurrentInstance().addMessage("autor", new FacesMessage("Livro deve ter um Autor"));//id do xml do component
            return;
        }

        new DAO<Livro>(Livro.class).adiciona(this.livro);

        // aqui criamos um novo livro vazio pra limpar os campos e o id
        this.livro = new Livro(); 
    }