Persist object in CRUD JSF + CDI + JPA

Asked

Viewed 529 times

2

I am making a simple CRUD, using JSF, JPA and CDI.

I have two screens:

  • A screen with a datatable listing the data, in each row has the edit and delete button, at the beginning of the screen has an insert button, the boões edit and insert direct to the second screen.
  • The second screen is the form, with the inputs and save button

I have a bean ViewScoped to take care of both screens and step the parameters from one screen to the other with the f:setPropertyActionListener, everything works according to both insert and edit.

Now when the bean validating some business rule prevents the user from editing (in this case returning null to the action of the button), the screen returns for the user to correct the data and submit again, but when this happens mine EntityManager has already closed, as it is configured to live in the scope of request (what for bank control is great).

Right now the mistake is org.hibernate.PersistentObjectException: detached entity passed to persist.

If the bean does not accuse error editing works, since Entitymanager is already open, because it was used to load the object that is displayed on the screen.

Changing the scope of Entitymanager would create the problem of having to manage it when it closes and I don’t want that.

I wonder what I can do to get around this problem and how you solve it.


Producer of the Entitymanager

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


Bean that takes care of the list screen and the form.

@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;
    }

}


Edit from item in data listing.

<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>


Receiving the parameter in the form.

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


Convert

@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;
    }
}

1 answer

0

Man, here I wear it like this.

@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();
    }

}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.