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 Tue, 11 Dec 2007 15:26:07 GMT

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-tp14216438p14276253.html
Sent from the OpenJPA Developers mailing list archive at Nabble.com.


Mime
View raw message