EJB 3.1 + Hibernate + JSF - detached entity passed to persist

0

Hej!
Mam problem ze zrozumieniem działania Hibernate'a i w związku z tym błędy w aplikacji i nie mogę niestety ruszyć dalej...

Mam w aplikacji następujące encje:

@Entity
public class Wydanie implements Serializable {
    
    @OneToMany(mappedBy = "wydanieId",fetch= FetchType.EAGER, orphanRemoval=true, cascade= CascadeType.ALL)
    private List<WydaniePrzesylka> wydaniePrzesylkaList;
}
@Entity
public class WydaniePrzesylka implements Serializable {
    @Column(name = "data_wydania")
    @Temporal(TemporalType.TIMESTAMP)
    private Date dataWydania;
    @Column(name = "data_zwrotu")
    @Temporal(TemporalType.TIMESTAMP)
    private Date dataZwrotu;

    @JoinColumn(name = "wydanie_id", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false,cascade= CascadeType.ALL)
    private Wydanie wydanieId;
    
    @JoinColumn(name = "przesylka_id", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false,cascade = CascadeType.ALL)
    private Przesylka przesylkaId;
}
   
@Entity
public class Przesylka implements Serializable {
private static final long serialVersionUID = 1L;

    @Column(name = "nr_przesylki")
    @Size(min=1,message="Brak numeru przesylki")
    private String nrPrzesylki;
    @Basic(optional = true)
    @Column(name = "rezerwacja")
    private boolean rezerwacja;
	
    @OneToMany(mappedBy = "przesylkaId",cascade= CascadeType.ALL)
    private List<WydaniePrzesylka> wydaniePrzesylkaList;

}

Oraz EJBean'a z poniższą metodą którą wywołuję z JSF poprzez ManagedBean'a

@Stateless
public class WydanieDAO implements IDAOWydanie{

    @PersistenceContext
    EntityManager em;
    
    @Override
    public void saveWydanie(Wydanie w) {
        if (w.getId() == null) {
            em.persist(w);
            System.out.println("persist");
        } else {
            System.out.println("merge start");
				em.merge(w);
            System.out.println("merge stop");
        }
    }

Przy wykonywaniu metody już po wypluciu na konsolę "merge stop"
Dostaję wyjątek:

WARNING: A system exception occurred during an invocation on EJB WydanieDAO method public void dao.implementations.WydanieDAO.saveWydanie(models.entities.Wydanie)
javax.ejb.EJBException
	at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:5194)
	at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5092)
	at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4880)
	at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2039)
	at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1990)
	at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
	at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
	at $Proxy157.saveWydanie(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:305)
	at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
	at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
	at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:299)
	at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:126)
	at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:62)
	at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:125)
	at dao.implementations.org$jboss$weld$bean-web-SessionBean-WydanieDAO_$$_WeldProxy.saveWydanie(org$jboss$weld$bean-web-SessionBean-WydanieDAO_$$_WeldProxy.java)
	at controllers.PrzesylkaController.saveWydanie(PrzesylkaController.java:160)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.el.parser.AstValue.invoke(AstValue.java:234)
	at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
	at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43)
	at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:56)
	at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:153)
	at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
	at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:769)
	at javax.faces.component.UICommand.broadcast(UICommand.java:300)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
	at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:619)
Caused by: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: models.entities.Przesylka
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1215)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1148)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1154)
	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
	at dao.implementations.WydanieDAO.saveWydanie(WydanieDAO.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
	at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
	at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5367)
	at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
	at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:801)
	at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
	at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:46)
	at sun.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:862)
	at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:801)
	at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
	at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
	at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
	at sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:862)
	at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:801)
	at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:371)
	at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5339)
	at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5327)
	at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
	... 58 more
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: models.entities.Przesylka
	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127)
	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:799)
	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:791)
	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:48)
	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
	at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
	at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:450)
	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:282)
	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:799)
	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:791)
	at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:48)
	at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
	at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
	at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
	at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
	at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
	at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
	at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:475)
	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:353)
	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
	at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
	at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
	at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
	at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
	at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
	... 87 more

Akcja polega na tym że poprzez formularz tworzę obiekt Wydanie który wypełniam podstawowymi danymi oraz dzięki tabelce na widoku z multiselect wypełniam kolekcję WydanaPrzesyłka.
Chciałbym aby przede wszystkim dodał się obiekt z kolekcją pojedyńczym poleceniem em.persist(Wydanie) dlatego też ustawiłem adnotacje Cascade, w bazie również wszystkie contrainty FK i cascade są ustawione
Na dodatek następne moje pytanie:
Chciałbym aby użytkownik miał możliwość edycji powyższego obiektu, potrafię go załadwoać do widoku JSF tyle że chciałbym cos takiego:
użytkownik przy dodaniu zaznaczył 3 obiekty WydanaPrzesyłka z tabeli, a następnie edytuje obiekt i odznacza 2 tak że został ostatecznie zaznaczony tylko 1 obiekt WydanaPrzesyłka.
Czy samo merge w tym momencie wystarczy? Czy muszę usunąć wszystkie obiekty WydanaPrzesyłka o ID rodzica Wydanie i dodać na nowo kolekcję?
Być moze coś źle pomapowałem... Jedno Wydanie ma wiele WydaniePrzesylka, zaś jedno WydaniePrzesyłka jest praktycznie 1-1 z Przesylka, ale zostawiłem tak jak mi podpowiedział Netbeans przy automatycznej generacji mapowania.
Dodam że dopiero rozpoczynam zabawę z JEE6 i sam niczego nie jestem pewien.
Przeszukałem google pod kątem tego błędu ale nic konkretnego pod mój przypadek nie znalazłem...
Każda encja pobiera ID z sekwencji, baza PostgreSQL.
Wiem że dużo pytań ale za jakąkolwiek wskazówkę, pomoc będe bardzo wdzieczny.

Środowisko:
Glassfish 3.1
Netbeans 7.0
JSF 2 + PrimeFaces
Hibernate 3.6.4
EJB 3.1

0

Zamiast persist użyj merge. Próbujesz utrwalić obiekt, który został odłączony od sesji. Przed utrwaleniem musi być z powrotem do sesji dołączony.

0

Merge rozni sie tym ze tworzy nowy graf obiektow w stanie persistent, i go zwraca jako wynik (a wlasciwie tylko czubek grafu, odpowiadajacy parametrowi). Nie zapomnij 'zapomniec' tego co przekazujesz jako parametr, i nadpisac tym co merge zwraca.

1 użytkowników online, w tym zalogowanych: 0, gości: 1