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 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 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 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 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