-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: EJB-2-EJB calls and failure to update entity in same session
PostPosted: Wed Apr 19, 2006 2:37 am 
Newbie

Joined: Wed Apr 19, 2006 12:41 am
Posts: 6
Here is a brief description of what I am trying to do and what the problem is. Any inputs would be greatly appreciated. Thanks !!
Code:
Hibernate Version:      3.1.2
JVM:               IBM 1.4.2
Server:               WAS 5.1.1
Platform               windows


Hibernate Config:
Code:
<property name="show_sql">true</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</property>
<property name="hibernate.connection.datasource">jdbc/bph</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereTransactionManagerLookup</property>
<property name="hibernate.transaction.flush_before_completion">false</property>
<property name="hibernate.transaction.auto_close_session">true</property>

I have 2 EJBs.

In EJB1, I load an entity and update it (this works fine).

EJB1 calls EJB2 (remote interface) passing the persistent entity across the remote boundary.
EJB2 runs inside the same transaction (and therefore same hibernate session) as initiated by EJB1. EJB2 does some more changes to the entity and attempts to update it. Now, here is the problem: I get a NonUniqueObjectException. After doing a lot of debugging, I came to the following conclusions. When an entity is passed from EJB1 to EJB2, it's identity hashcode has changed. The Entity which was loaded in EJB1 is just not the same as the entity being updated in EJB2. Hibernate uses System.identityHashCode(Object) to store entities in IdentityMap. When I serialize the entity from EJB1 to EJB2, it's identity hashcode has changed. The following code snippet is taken from IdentityMap.IdentityKey

Code:
      public int hashCode() {
         return System.identityHashCode(key);
      }


When I try to update (session.update(Object)) in EJB2, one of the lines executed in DefaultUpdateEventListener.performSaveOrUpdate(SaveOrUpdateEvent) is

Code:
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );


and this returns null (as identity hashcode has changed on serialization, the map cannot locate it). The conclusion is - entity Is Detached. But Why ?

So, it then goes further to find out that the entity is not unique since the follwing line throws the NonUniqueObjectException.

Code:
source.getPersistenceContext().checkUniqueness( key, entity );


in method DefaultSaveOrUpdateEventListener.performUpdate(..).
Possible solutions....

I have also tried to use session.contains(entity) but it returns false, since it uses the same logic of finding out entity entries (entityEntries.containsKey(entity) and identity hashcode).
I was hoping to see something like session.contains(class, key) or session.contains(object), that can actually tell me if an entity already exists in session or not!
Any opinions that can help me resolve this problem would be highly appreciated.

Thanks in advance !

_________________
Thanks,
Gautam


Top
 Profile  
 
 Post subject: Re-attaching a serialized persistent entity
PostPosted: Wed Apr 19, 2006 3:52 am 
Newbie

Joined: Wed May 11, 2005 3:05 am
Posts: 2
Location: Australia
We have also seen this problem that you describe with the same base configuration.

I assume you want contains() to tell you whether the entity is in the session or not so that your application code can do something like this:

Code:
If (session.contains(entity)
merge
else
update


As contains wont indicate whether the entity is in the entries map we used a different approach. Instead we tried update() and if update threw an exception used merge(). However this isnt ideal. Conceptionally we actually wanted the update behaviour. But were (and are) unsure how to
get update() to work in all situations.

The entity Hashcode changes as result of serialisation over a remote interface (although the hibernate session stays open, is in the same JTA transaction and also in the same server), the Identiy hashcode no longer matches and session.contains() checks a different map.

In our application we dont always know whether a read followed by an update is in one EJB, crosses 2 EJBSs or N EJBS. Its all within the server tier though and in 1 JTA txn. Ideally we would like to use session.update() in all these scenarios. We haven't intentially (or explicitly) detatched the entity from the udnerlying session.

Any advice in this matter would be appreciated.

regards,
Lara


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 19, 2006 6:52 pm 
Newbie

Joined: Wed Apr 19, 2006 12:41 am
Posts: 6
I thought of doing the same, however I realise that merge does not actually associate the entity with the session. Instead, you take the returned entity after doing session.merge(..) and pass that around instead (the entity that was passed as argument is no longer latest, we also use versioning). Since a calling program does not know whether a merge was done or an update was done, it must always re-load or re-assign the latest version returned from our data access object. Or maybe there could have been few other methods in Session like:

Code:
public void mergeOrUpdate(String entityName, Object object) throws HibernateException

public void mergeOrUpdate(Object object) throws HibernateException


Similar problem (like update) occurs with session.delete(Object) as well.

And we could use these methods with care...:)

_________________
Thanks,
Gautam


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 2:35 am 
Newbie

Joined: Wed Apr 19, 2006 12:41 am
Posts: 6
Currently, what we have done is that before each update or delete call of an entity in the DAO we call this piece of code, this gets around the problem. There are some assumptions in this, but works for the time being. The main being that we can successfully evict the entity if it is stored in entityEntries map.

Code:
        if(!getSession().contains(entity)) { // entity is detached!!
            // evict if same entity already exists via some other call over network!
            SessionStatistics statistics = getSession().getStatistics();
            Set entityKeys = statistics.getEntityKeys();
            if(entityKeys == null) {
                return false;
            }
            Iterator it = entityKeys.iterator();
            while(it.hasNext()) {
                EntityKey entityKey = (EntityKey) it.next();
                if(entityKey.getEntityName().equals(entity.getClass().getName()) &&
                    entity.getEntityKey().equals(entityKey.getIdentifier())) {
                   // do processing
                   Object object = getSession().get(entity.getClass(), entity.getEntityKey());
                   if(object != null) {
                       evict((Entity) object);
                       return true;
                   }
                }
            }
        }
       
        return false;


Hopefully, many others who have similar environments can make use of this code.


Cheers,
Gautam

_________________
Thanks,
Gautam


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.