I've spoken with Jackson12 offline regarding the problem. I think the real
problem he's hitting is related to OPENJPA-245 :
http://issues.apache.org/jira/browse/OPENJPA-245. The JIRA issue lists a
workaround by using the DetachedState annotation,
import org.apache.openjpa.persistence.DetachedState;
@Entity
@DetachedState(enabled=false)
public class Person {
. . .
}
Unfortunately I found the workaround after I wrote a patch which also seems
to resolve the problem. I'll post the patch and other observations to the
JIRA shortly.
-Mike
On Jan 9, 2008 9:13 AM, Kevin Sutter <[EMAIL PROTECTED]> wrote:
> Hi jackson12,
> Back in the saddle again after an extended Christmas vacation... :-)
>
> Any progress on this request? I took a quick look at your proposed patch
> and although you indicated that it worked for your scenario, at least one
> of
> our OpenJPA regression tests failed. So, we can't just drop your patch
> into
> OpenJPA. But, we would like to understand the situation and maybe the
> patch
> can be tweaked to get this resolved. No promises...
>
> In your last post, you indicated that you would create a small use case
> for
> this scenario. Any luck with that yet? That would definitely help with
> analyzing any proposed patches. And, we would have a regression test for
> this scenario.
>
> Thanks,
> Kevin
>
> On Dec 18, 2007 10:39 AM, jackson12 <[EMAIL PROTECTED]> wrote:
>
> >
> > I will create a small use case for this.
> >
> > thanks
> >
> > Patrick Linskey-2 wrote:
> > >
> > > Hi,
> > >
> > > Is it possible for you to post an example of the failure behavior? I'd
>
> > > like to a) see why it's not Just Working, and b) have a regression
> > > test in place if this fix does the trick.
> > >
> > > -Patrick
> > >
> > > On Dec 15, 2007 5:55 AM, jackson12 < [EMAIL PROTECTED]> wrote:
> > >>
> > >> 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 < [EMAIL PROTECTED]> 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 < [EMAIL PROTECTED]>
> 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 < [EMAIL PROTECTED]>
> > >> 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.
> > >>
> > >>
> > >
> > >
> > >
> > > --
> > > Patrick Linskey
> > > 202 669 5907
> > >
> > >
> >
> > --
> > View this message in context:
> >
> http://www.nabble.com/merge-only-works-with-managed-entity-tp14216438p14400747.html
> > Sent from the OpenJPA Developers mailing list archive at Nabble.com.
> >
> >
>