openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jackson12 <kemin_c...@yahoo.com>
Subject Re: merge only works with managed entity
Date Fri, 14 Dec 2007 21:55:06 GMT

After making some small changes in OpenJPA source code, I am able to call a
merge() method with an entity that's not detached. This allows our code that
works in JBoss also work in IBM Websphere.

Here is the change:

in the attach method of class VersionAttachStrategy
replace line 76:
     boolean isNew = !broker.isDetached(pc); 
with:
        Object id = getDetachedObjectId(manager, toAttach);
        boolean isNew = true;
        if (id != null)	 isNew = false;

Do you see any issues with this change? 

Thanks for the help!



jackson12 wrote:
> 
> Kevin, Patrick,
> 
> Any update on this?
> 
> We want to quickly decide if we can switch to OpenJPA with IBM Websphere,
> this is currently our show stopper.
> 
> 
> 
> jackson12 wrote:
>> 
>> Kevin,
>> 
>> What you described is exactly the problem. 
>> 
>> But unfortunately we don't have the luxury to use the approach you
>> proposed (find-->detach-->merge)
>> because our application is a struts based web application, and on the web
>> tier we have a different set of DTOs to hold the changes from end user
>> and currently we are only migrating our backend to use EJB3.
>> 
>> so at someplaces, we have to copy the values from DTO to managed or
>> detached entities, but I don't know any "smarter copy" that can also
>> maintain the extra code in the managed or detached entity.
>> 
>> This should be a very common scenarios. Please let me know if you or
>> Patrick have some other ideas. 
>> 
>> Thanks in advance!
>> 
>> 
>> 
>> Kevin Sutter wrote:
>>> 
>>> jackson12,
>>> I understand your problem.  Since the Person object holds a nested
>>> Address
>>> object, when you use the copyProperties() method, the nested managed
>>> Address
>>> object gets overwritten with an unmanaged instance.  Right?
>>> 
>>> The copyProperties() method is kind of simple.  It just copies attribute
>>> by
>>> attribute.  Since it sees an Address attribute, it just copies the new
>>> Address attribute right on top of the managed one.  The problem here is
>>> that
>>> the managed instance of Address has OpenJPA state associated with it. 
>>> When
>>> the copyProperties() is invoked, we lose all of that state data (and
>>> code)
>>> due to the unmanaged Address object.  Hibernate's method of keeping
>>> track of
>>> object state must be different from the way that OpenJPA does it.
>>> 
>>> What it sounds like you need is a smarter copyProperties() method.  One
>>> that
>>> will copy the simple property values, but then traverse into the nested
>>> managed objects to do it's own copyProperties().  But, then if these
>>> nested
>>> objects have additional nested managed objects, you run into the same
>>> complication.
>>> 
>>> How about using the merge() operation to accomplish this task?  Instead
>>> of
>>> just creating new unmanaged instances of your Person objects, do a find
>>> operation to get them managed by your persistence context.  Then, detach
>>> the
>>> entities and do whatever updates you want to these detached instances. 
>>> When
>>> you are ready to copy them back in to the persistence context, call the
>>> merge() method and let the changes merge back into the persistence
>>> context.
>>> This would seem to be along the lines of processing that you are looking
>>> for, but from a different angle.
>>> 
>>> I'll copy Patrick on this reply just to see if he has some other ideas.
>>> 
>>> Thanks,
>>> Kevin
>>> 
>>> 
>>> On Dec 11, 2007 8:02 AM, jackson12 <kemin_chen@yahoo.com> wrote:
>>> 
>>>>
>>>> Kevin,
>>>>
>>>> Thanks again for the clarification.
>>>>
>>>> Here is the scenario for the nested properties.
>>>>
>>>> Suppose I have an entity Person that holds a nested entity Address.
>>>> Assume
>>>> I
>>>> use find() method to load
>>>> the Person entity with Address. Now in order to apply the changes, we
>>>> normally use
>>>>
>>>>     PropertyUtils.copyProperties(managedPerson, inputPerson);
>>>>
>>>> or
>>>>    BeanUtils.copyProperties(managedPerson, inputPerson);
>>>>
>>>> but these copyProperties method will make the nested Address entity
>>>> non-managed (because the Address reference will be replaced by , and
>>>> hence
>>>> OpenJPA will throw exception when I call the merge() method later. In
>>>> order
>>>> to bypass this, we have to copy field by field from inputPerson to
>>>> managedPerson including the nested entity. This makes the code very
>>>> error
>>>> prone and ugly.
>>>>
>>>> JBoss's implementation does not require the inputPerson to be managed
>>>> or
>>>> detached, I know this maybe beyond JPA1.0 spec, but it is really very
>>>> helpful.
>>>>
>>>> Do I misunderstand anything?
>>>>
>>>> thanks a lot
>>>>
>>>>
>>>>
>>>> Kevin Sutter wrote:
>>>> >
>>>> > jackson12,
>>>> > If I am understanding your scenario correctly, your userProfile input
>>>> > parameter is an unmanaged entity, but the key for this entity does
>>>> already
>>>> > exist in the database.  So, when you attempt to do the merge()
>>>> processing
>>>> > (and subsequent transaction commit), you are getting a "duplicate
>>>> key"
>>>> > exception from Oracle.
>>>> >
>>>> > Calling merge() with a new unmanaged entity acts like a persist()
>>>> call
>>>> and
>>>> > adds it to the persistence context.  The persist() method is intended
>>>> for
>>>> > new entities that do not currently exist in the database.
>>>> >
>>>> > So, on the surface, your scenario seems to be acting as I would
>>>> expect
>>>> > with
>>>> > any JPA implementation.  But, you have indicated that JBoss'
>>>> Hibernate
>>>> is
>>>> > processing as you had hoped.  Based on my understanding of the spec
>>>> and
>>>> > your
>>>> > scenario, I think you are getting lucky with Hibernate.
>>>> >
>>>> > I would suggest doing the find() operation first to properly load the
>>>> > entity
>>>> > into the persistence context and then do your updates.  You can
>>>> always
>>>> > detach this entity from the persistence context, if necessary, for
>>>> other
>>>> > processing and then merge it back in later.  Since the merge() would
>>>> be
>>>> > operating on a known, detached entity, an update operation will be
>>>> > performed
>>>> > instead of the insert.
>>>> >
>>>> > A few other observations...  Remember that the merge() operation
>>>> returns
>>>> > the
>>>> > managed entity as a return value.  The original entity that you
>>>> passed
>>>> > into
>>>> > the merge() method is not managed.  So, if you want any state changes
>>>> to
>>>> > the
>>>> > entity to be properly maintained and persisted, you need to use the
>>>> > returned
>>>> > managed instance of the entity from the merge() operation.
>>>> >
>>>> > You also mentioned how the nested properties are not managed.  This
>>>> may
>>>> be
>>>> > related to the above observation.  Another possibility is that you
>>>> need
>>>> to
>>>> > declare whether you want the merge processing to be cascaded to the
>>>> > objects
>>>> > pointed to by the entity.  You would specify this on the relationship
>>>> > annotation via the cascade=CascadeType.MERGE element.  You haven't
>>>> > provided
>>>> > the complete entity definition, so I'm not exactly sure how you have
>>>> these
>>>> > entity types defined.
>>>> >
>>>> > Hope this information helps.
>>>> >
>>>> > Good luck,
>>>> > Kevin
>>>> >
>>>> > On Dec 7, 2007 11:50 AM, jackson12 <kemin_chen@yahoo.com> wrote:
>>>> >
>>>> >>
>>>> >> Thanks Kevin for your prompt response.
>>>> >> Here is a simple use case we have:
>>>> >> within an EJB , we have the following method:
>>>> >>
>>>> >> public UserProfile updateUserProfile(UserProfile userProfile) {
>>>> >>                return getProfileDAO().update(userProfile);
>>>> >> }
>>>> >>
>>>> >> when this method is called, the input parameter has all of the
>>>> values
>>>> >> including the key, but we got a runtime exception because it's
>>>> trying
>>>> to
>>>> >> insert userProfile into database.
>>>> >>
>>>> >> org.apache.openjpa.persistence.PersistenceException: ORA-00001:
>>>> unique
>>>> >> constraint (VPDNGDITR17.PK_SECURITY_USER_PROFILE) violated
>>>> FailedObject:
>>>> >> prepstmnt 1645109774 INSERT INTO SECURITY_USER_PROFILE (OID,
>>>> >> MODIFIED_BY_USER, ........
>>>> >>
>>>> >> After we change the code to the following, it works fine:
>>>> >>        public UserProfile updateUserProfile(UserProfile userProfile)
>>>> {
>>>> >>                UserProfileDAO profileDAO = getProfileDao();
>>>> >>                UserProfile tmpUserProfile =
>>>> >> profileDAO.getUserProfile(userProfile.getName());
>>>> >>                PropertyUtils.copyProperties(tmpUserProfile,
>>>> userProfile);
>>>> >>                return getProfileDao().update(tmpUserProfile);
>>>> >>        }
>>>> >>
>>>> >> Here is the update method of ProfileDAO:
>>>> >>
>>>> >> public T update(T entity)
>>>> >> {
>>>> >>       getEntityManager().merge(entity);
>>>> >> }
>>>> >>
>>>> >> When the input parameter has nested object, even the above approach
>>>> won't
>>>> >> work any more, because PropertyUtils.copyProperties will make the
>>>> nested
>>>> >> object not managed anymore.
>>>> >>
>>>> >> Thanks a lot
>>>> >>
>>>> >>
>>>> >> Kevin Sutter wrote:
>>>> >> >
>>>> >> > jackson12,
>>>> >> > Could you be more specific with your example?  We have various
>>>> >> testcases
>>>> >> > that do this exact process of merging in non-managed entities
>>>> (without
>>>> >> > first
>>>> >> > retrieving the entity from the DB).   Could you further explain
>>>> your
>>>> >> test
>>>> >> > scenario and what results you are getting?
>>>> >> >
>>>> >> > Thanks,
>>>> >> > Kevin
>>>> >> >
>>>> >> > On Dec 7, 2007 11:12 AM, jackson12 <kemin_chen@yahoo.com>
wrote:
>>>> >> >
>>>> >> >>
>>>> >> >> Hi, We are trying to migrate our JBoss EJB3 application
to IBM
>>>> >> websphere
>>>> >> >> with
>>>> >> >> OpenJPA. We noticed in OpenJPA, the merge method does not
work
>>>> with
>>>> >> >> non-managed entity. You have to retrieve the entity from
DB, make
>>>> some
>>>> >> >> changes and then call merge. But with JBoss's implementation,
you
>>>> >> don't
>>>> >> >> have
>>>> >> >> to retrieve the entity from DB first. the merge method
works fine
>>>> for
>>>> >> >> non-managed entity.
>>>> >> >>
>>>> >> >> Is there anyway for OpenJPA to work the same way as JBoss's
JPA
>>>> >> >> implementation on this part? or is there a way in OpenJPA
to make
>>>> a
>>>> >> >> non-managed entity managed?
>>>> >> >>
>>>> >> >> thanks in advance
>>>> >> >> --
>>>> >> >> View this message in context:
>>>> >> >>
>>>> >>
>>>> http://www.nabble.com/merge-only-works-with-managed-entity-tf4963245.html#a14216438
>>>> >> >> Sent from the OpenJPA Developers mailing list archive at
>>>> Nabble.com.
>>>> >> >>
>>>> >> >>
>>>> >> >
>>>> >> >
>>>> >>
>>>> >> --
>>>> >> View this message in context:
>>>> >>
>>>> http://www.nabble.com/merge-only-works-with-managed-entity-tf4963245.html#a14217307
>>>> >> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>>>> >>
>>>> >>
>>>> >
>>>> >
>>>>
>>>> --
>>>> View this message in context:
>>>> http://www.nabble.com/merge-only-works-with-managed-entity-tp14216438p14274498.html
>>>> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>>>>
>>>>
>>> 
>>> 
>> 
>> 
> 
> 

-- 
View this message in context: http://www.nabble.com/merge-only-works-with-managed-entity-tp14216438p14339820.html
Sent from the OpenJPA Developers mailing list archive at Nabble.com.


Mime
View raw message