No way to delete an instance when executing on a JEE server, it works fine in a junit test.
Env :
glassfish 3.0.1
hibernate 3.5.5
spring 3.0.4
Here is the exception
Code:
ava.lang.IllegalArgumentException: Removing a detached instance fr.tm.ima.metier.afo.exima.bo.ProfilCollaborateurBO#
at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:65)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:108)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:948)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:926)
at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:698)
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.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy175.remove(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.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy175.remove(Unknown Source)
at fr.tm.ima.metier.afo.exima.ba.collaborateur.UpdateCollaborateurBA.execute(UpdateCollaborateurBA.java:112)
...
Unlike the exception says, the object is not detached because i've just read it with the same entitymanager
Code:
Query req = em.createNamedQuery("getProfilByCollaborateurId");
req.setParameter("numCollaborateur", new Integer(pCollaborateur.getIdCollaborateur()));
List<ProfilCollaborateurBO> profilsBase = (List<ProfilCollaborateurBO>) req.getResultList();
for (ProfilCollaborateurBO profilCollaborateurBO : profilsBase) {
em.remove(profilCollaborateurBO);
}
I even tried to re-read it,
Code:
Query req = em.createNamedQuery("getProfilByCollaborateurId");
req.setParameter("numCollaborateur", new Integer(pCollaborateur.getIdCollaborateur()));
List<ProfilCollaborateurBO> profilsBase = (List<ProfilCollaborateurBO>) req.getResultList();
for (ProfilCollaborateurBO profilCollaborateurBO : profilsBase) {
ProfilCollaborateurBO bo = em.find(ProfilCollaborateurBO.class, profilCollaborateurBO.getId());
em.remove(bo);
}
The transaction is supplied by the container via spring.
It 's like the entitymanager create a new connection or clean its session for each database access. It can't be the case because the transaction works fine for everything else (update, insert, commit/rollback).
It could be a spring configuration problem, so here is my spring configuration
Code:
<context:annotation-config />
<tx:annotation-driven/>
<jee:jndi-lookup id="dataSource" jndi-name="..."/>
<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<!-- utilise la version multiple même si ici ce n'est pas utile -->
<property name="persistenceXmlLocations">
<list>
<value>classpath*:persistenceCUAD.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="dataSource" />
<property name="persistenceUnitPostProcessors">
<list>
<bean class="...spring.config.MappingPostProcessor">
<property name="mappings" ref="mappings" />
</bean>
</list>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="cuadPU"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DB2400Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
...
and the persitence.xml
Code:
<persistence-unit name="cuadPU" transaction-type="JTA">
</persistence-unit>
The main difference in the junit test is the transaction-type which is "RESOURCE_LOCAL" and the datasource which is local
Code:
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.ibm.as400.access.AS400JDBCDriver" />
<property name="url" value="jdbc:as400://..." />
<property name="username" value="..." />
<property name="password" value="..." />
</bean>
Thanks for any help
Fred
Edit : same behaviour on a websphere 7.0
Edit2 : after a little debug, i noticed the entitymanager's persistenceContext was always empty even after a request. Using the underlying session (wth em.getDelegate()) with the same code above, the persistencecontext works correctly. So the question is why the entitymanager's persistenceContext is always empty ? is it normal ? i missed something in documentation, is there any flag to activate to use this persistencecontext ?
(I did not mentioned above: this code is inside an EJB3 stateless)