TransWikia.com

Persistir objeto em CRUD JSF + CDI + JPA

Stack Overflow em Português Asked by Gleison on October 14, 2020

Estou fazendo um CRUD simples, usando JSF, JPA e CDI.

Tenho duas telas:

  • Uma tela com um datatable listando os dados, em cada linha tem o botão editar e excluir, no inicio da tela tem um botão inserir, os boões editar e inserir direcionam para a segunda tela.
  • A segunda tela é o formulário, com os inputs e o botão de salvar

Tenho um bean ViewScoped para cuidar de ambas telas e passo os parâmetros de uma tela para a outra com o f:setPropertyActionListener, tudo funciona de acordo, tanto o inserir quanto o editar.

Agora quando o bean ao validar alguma regra de negócio impede o usuário de editar (neste caso retornando null ao action do botão), a tela volta para o usuário corrigir o dado e submeter novamente, mas quando isso acontece o meu EntityManager já fechou, pois ele esta configurado para viver no escopo de request (o que para o controle do banco é ótimo).

Neste momento o erro é org.hibernate.PersistentObjectException: detached entity passed to persist.

Se o bean não acusa erro o editar funciona, visto o EntityManager já estar aberto, pois ele foi usado para carregar o objeto que é apresentado na tela.

Mudar o escopo do EntityManager criaria o problema de ter que gerenciá-lo quando fechar e eu não quero isso.

Gostaria de saber o que posso fazer pra contornar esse problema e como voces resolvem isso.


Produtor do EntityManager

@Produces
@RequestScoped
public EntityManager createEntityManager() {
    return factory.createEntityManager();
}
public void closeEntityManager(@Disposes EntityManager manager) {
    manager.close();
}

Bean que cuida da tela de listar e do formulário.

@Named
@ViewScoped
public class PaisMB implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private PaisFA paisFa;
    private LazyDataModel<Pais> lazyModel = null;
    private Pais paisSelecionado = null;

    public LazyDataModel<Pais> getLazyModel() {
        if (lazyModel == null) {
            lazyModel = paisFa.listaPais();
        }
        return lazyModel;
    }

    public Pais getPaisSelecionado() {
        if (paisSelecionado == null) {
            paisSelecionado = new Pais();
        }
        return paisSelecionado;
    }

    public void setPaisSelecionado(Pais paisSelecionado) {
        this.paisSelecionado = paisSelecionado;
    }

    public void deletePaisSelecionado() {
        try {
            paisFa.deletePais(getPaisSelecionado());
            JSFUtil.sendInfoMessageToUser("O país "" + getPaisSelecionado().getNome() + "" foi deletado com sucesso.");
        } catch (Exception ex) {
            (...)
        }
    }

    public String salvarPaisSelecionado() {
        try {
            paisFa.savePais(getPaisSelecionado());
            JSFUtil.sendInfoMessageToUser("O país "" + getPaisSelecionado().getNome() + "" foi salvo com sucesso.");
            return "/paisLista?faces-redirect=true";
        } catch (Exception ex) {
            (...)
        }
        return null;
    }

}

Item editar do na listagem de dados.

<p:menuitem value="Editar" icon="fa fa-edit" action="paisForm?faces-redirect=true&amp;includeViewParams=true">
    <f:setPropertyActionListener target="#{paisMB.paisSelecionado}" value="#{paisMB.paisSelecionado}" />
</p:menuitem>

Recebendo o parâmetro no formulário.

<f:metadata>
    <f:viewParam name="pais" value="#{paisMB.paisSelecionado}" converter="#{dbEntityCO}" />
</f:metadata>

Converter

@Named("dbEntityCO")
@ApplicationScoped
public class DBEntityCO implements Converter {

    @Inject
    private EntityManager entityManager;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        // aqui usa o EntityManager
        (...)
        return objeto;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        (...)
        return string;
    }
}

One Answer

Cara, aqui eu uso assim.

@ApplicationScoped
public class EntityManagerProducer {

    private EntityManagerFactory factory;

    public EntityManagerProducer() {
        factory = Persistence.createEntityManagerFactory("Thunder");
    }

    @Produces
    @RequestScoped
    public EntityManager createEntityManager(){
        return factory.createEntityManager();
    }

    public void closeEntityManager(@Disposes EntityManager manager){
        manager.close();
    }

}

Answered by Jonathan on October 14, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP