persistence@glassfish.java.net

re : Not detached after use EntityManager's query in non-transactional mode

From: Kenneth Saks <Kenneth.Saks_at_Sun.COM>
Date: Thu, 06 Apr 2006 10:58:05 -0400

  Wonseok Kim wrote:

>
>
> If you have thought about it, plz let me know...

Hi Wonseok,

I agree the spec is a bit light on the requirements for non-tx usage on
a container-managed entity manager. An application-managed
EntityManager seems better suited for non-transactional queries. The
intent was that the container side of the container/provider contracts
could be implemented without having to proxy the Query object. I filed
a glassfish issue to track this.

https://glassfish.dev.java.net/issues/show_bug.cgi?id=552

Thanks.

 --ken

>
>
> On 4/5/06, *Kenneth Saks* < Kenneth.Saks_at_sun.com
> <mailto:Kenneth.Saks_at_sun.com>> wrote:
>
> Wonseok Kim wrote:
> The transaction-scoped EntityManager can be used in
> non-transaction mode.
> And the loaded entities are detached after method call.(Java
> Persistence API spec 5.6.1)
>
> So if I get an entity by query as follows, the entity should be
> detached.
> Hi Wonseok,
>
> Spec 5.6.1 says "If the EntityManager is invoked outside of a
> transaction, any
> entities loaded from the database will immediately become detached
> at the
> end of the method call". Your example is making that assumption
> for the
> Query object, not the EntityManager. This issue was discussed
> with the
> spec leads and the current implementation was validated as
> compliant.
>
> It's true that there are possible alternative implementations that
> involve varying
> amounts of proxying the Query object. That's something we're
> considering
> for a future release.
>
> --ken
>
>
> @PersistenceContext(type = TRANSACTION)
> private EntityManager em1;
>
> Person person = (Person)em.createQuery("SELECT p FROM Person p
> WHERE p.id=1").getSingleResult();
> // person should be detached entity
>
> boolean managed = em.contains(person); // should be false
>
> But the result is true(managed) in current build.
>
> Because com.sun.enterprise.util.EntityManagerWrapper createQuery
> methods are implemented in a wrong way like:
>
> public Query createQuery(String ejbqlString) {
> Query returnValue = null;
> try {
> returnValue = _getDelegate().createQuery(ejbqlString);
> } finally {
> if( delegateInfo.nonTxEntityManager ) {
> nonTxEntityManager.clear();
> }
> }
> return returnValue;
> }
>
> As you see, after making Query object, it is clearing underlying
> persistence context - meaningless!
> It should be cleared after query execution like
> Query.getSingleResult().
>
> This can be fixed by using Query wrapper in case of non-tx mode.
>
> The proposed fix is this: (I attached source files)
>
>Index: src/java/com/sun/enterprise/util/EntityManagerWrapper.java
>===================================================================
>RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/enterprise/util/EntityManagerWrapper.java,v
>
>
>
>retrieving revision 1.9
>*diff -r1.9 EntityManagerWrapper.java*
>*260,265c260,262*
>< try {
>< returnValue = _getDelegate().createQuery(ejbqlString);
>< } finally {
>< if( delegateInfo.nonTxEntityManager ) {
>< nonTxEntityManager.clear();
>< }
>*---*
>> returnValue = _getDelegate().createQuery(ejbqlString);
>> if( delegateInfo.nonTxEntityManager ) {
>> returnValue = new QueryWrapper(returnValue, true, nonTxEntityManager);
>*272,277c269,271*
>< try {
>< returnValue = _getDelegate().createNamedQuery(name);
>< } finally {
>< if( delegateInfo.nonTxEntityManager ) {
>< nonTxEntityManager.clear();
>< }
>*---*
>> returnValue = _getDelegate().createNamedQuery(name);
>> if( delegateInfo.nonTxEntityManager ) {
>> returnValue = new QueryWrapper(returnValue, true, nonTxEntityManager);
>*284,289c278,280*
>< try {
>< returnValue = _getDelegate().createNativeQuery(sqlString);
>< } finally {
>< if( delegateInfo.nonTxEntityManager ) {
>< nonTxEntityManager.clear();
>< }
>*---*
>> returnValue = _getDelegate().createNativeQuery(sqlString);
>> if( delegateInfo.nonTxEntityManager ) {
>> returnValue = new QueryWrapper(returnValue, true, nonTxEntityManager);
>*296,302c287,290*
>< try {
>< returnValue = _getDelegate().createNativeQuery
>< (sqlString, resultClass);
>< } finally {
>< if( delegateInfo.nonTxEntityManager ) {
>< nonTxEntityManager.clear();
>< }
>*---*
>> returnValue = _getDelegate().createNativeQuery
>> (sqlString, resultClass);
>> if( delegateInfo.nonTxEntityManager ) {
>> returnValue = new QueryWrapper(returnValue, true, nonTxEntityManager);
>*309,315c297,300*
>< try {
>< returnValue = _getDelegate().createNativeQuery
>< (sqlString, resultSetMapping);
>< } finally {
>< if( delegateInfo.nonTxEntityManager ) {
>< nonTxEntityManager.clear();
>< }
>*---*
>> returnValue = _getDelegate().createNativeQuery
>> (sqlString, resultSetMapping);
>> if( delegateInfo.nonTxEntityManager ) {
>> returnValue = new QueryWrapper(returnValue, true, nonTxEntityManager);
>
>
> *QueryWrapper.java*
> package com.sun.enterprise.util;
>
> import javax.persistence.Query;
> import javax.persistence.TemporalType;
> import javax.persistence.FlushModeType;
> import javax.persistence.EntityManager;
> import java.util.List;
> import java.util.Date;
> import java.util.Calendar;
>
> /**
> * Query wrapper used in non transaction mode.
> *
> * @author Wonseok Kim (guruwons_at_tmax.co.kr
> <mailto:guruwons_at_tmax.co.kr>)
> */
> public class QueryWrapper implements Query {
> private Query delegate;
> private boolean nonTxMode;
> private EntityManager nonTxEntityManager;
>
> QueryWrapper(Query delegate, boolean nonTxMode, EntityManager
> nonTxEntityManager){
> this.delegate = delegate;
> this.nonTxMode = nonTxMode;
> this.nonTxEntityManager = nonTxEntityManager;
> }
>
> public List getResultList() {
> try {
> return delegate.getResultList();
> } finally {
> if(nonTxMode){
> nonTxEntityManager.clear();
> }
> }
> }
>
> public Object getSingleResult() {
> try {
> return delegate.getSingleResult();
> } finally {
> if(nonTxMode){
> nonTxEntityManager.clear();
> }
> }
> }
>
> public int executeUpdate() {
> return delegate.executeUpdate();
> }
>
> public Query setMaxResults(int maxResult) {
> delegate.setMaxResults(maxResult);
> return this;
> }
>
> public Query setFirstResult(int startPosition) {
> delegate.setFirstResult(startPosition);
> return this;
> }
>
> public Query setHint(String hintName, Object value) {
> delegate.setHint(hintName, value);
> return this;
> }
>
> public Query setParameter(String name, Object value) {
> delegate.setParameter(name, value);
> return this;
> }
>
> public Query setParameter(String name, Date value,
> TemporalType temporalType) {
> delegate.setParameter(name, value, temporalType);
> return this;
> }
>
> public Query setParameter(String name, Calendar value,
> TemporalType temporalType) {
> delegate.setParameter(name, value, temporalType);
> return this;
> }
>
> public Query setParameter(int position, Object value) {
> delegate.setParameter(position, value);
> return this;
> }
>
> public Query setParameter(int position, Date value,
> TemporalType temporalType) {
> delegate.setParameter(position, value, temporalType);
> return this;
> }
>
> public Query setParameter(int position, Calendar value,
> TemporalType temporalType) {
> delegate.setParameter(position, value, temporalType);
> return this;
> }
>
> public Query setFlushMode(FlushModeType flushMode) {
> delegate.setFlushMode(flushMode);
> return this;
> }
> }
>
>
>------------------------------------------------------------------------
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail:
>
>dev-unsubscribe_at_glassfish.dev.java.net <mailto:dev-unsubscribe_at_glassfish.dev.java.net>
>For additional commands, e-mail: dev-help_at_glassfish.dev.java.net <mailto:dev-help_at_glassfish.dev.java.net>
>
>
>
>