| Summary: | EntityManager found stale entity after flush and clear | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Product: | z_Archived | Reporter: | Daniel Lo <daniel.lo> | ||||||||
| Component: | Eclipselink | Assignee: | Nobody - feel free to take it <nobody> | ||||||||
| Status: | CLOSED FIXED | QA Contact: | |||||||||
| Severity: | normal | ||||||||||
| Priority: | P3 | CC: | douglas.clarke, eclipselink.orm-inbox, SebTardif, tom.ware | ||||||||
| Version: | unspecified | ||||||||||
| Target Milestone: | --- | ||||||||||
| Hardware: | All | ||||||||||
| OS: | Linux | ||||||||||
| Whiteboard: | |||||||||||
| Attachments: |
|
||||||||||
Created attachment 173786 [details]
event-listener work-around with supporting test cases
This issue was reproduced in 2.1.0 Triaging. Is it possible to provide the persistence unit that recreates this problem? Created attachment 176392 [details]
Proposed fix - EclipseLink 2.1 stream
The patch above causes objects that could be changed in a cleared unit of work to be constructed in the UnitOfWork directly from the database forgoing the SharedCache. The behavior will be different depending on your settings for FLUSH_CLEAR_CACHE on your EntityManager. For FlushClearCache.Drop - As indicated in the documentation, you will get objects from teh shared cache For FlushClearCache.DropInvalidate(default) - We will build from the databse to the unit of work, if the class of the object being queried is set to be invalidated due to the call to clear For FlushClearCache.Merge - We will build from the database to the unit of work if the class of the object being queried is included in the cumulative change set created as a result of the call to clear. Note: Although it would be possible to identify individual objects in the change set, we are dealing with queries that may not be querying by PK and therefore must consider the possibility that all objects of a particular class are affected. (Unfortunately our default readFromDB to UOW functionality does not help us because it only applies to Native queries and Update All queries) Created attachment 176485 [details]
Updated patch
Checked into trunk Similar fix will be put in 2.1.2 when the stream opens A fix was checked in to have Object build directly to the UOW in the case that a clear has been run with certain FlushMode settings Reviewed by Gordon Yorke Added 3 tests to the EntityManagerJunitTestSuite for the annotations model Fix checked into 2.1.2 The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |
Build Identifier: 2.0.2.v20100323-r6872 In J2EE environment, within a transaction, after we updated an entity, we invoked the EntityManager.flush() then the EntityManager.clear() API, before we commit the transaction, we did a EntityManager.find() which returned the previous entity version before the update, this seems to a bug, since the changes have been flushed to the database, the EntityManager.find() should retrieve and return the latest version instead of the previous version. Here is the test code and the logs: UserTransaction ut = getTransaction(); ut.begin(); EntityManager em = getEntityManager(); System.out.println("1. ***** Before merge: isManaged = " + em.contains(dataTypes) + " version = " + dataTypes.getEntityVersion() + " aString = " + dataTypes.getAString()); dataTypes.setAString("999"); dataTypes = em.merge(dataTypes); em.flush(); System.out.println("2. ***** After flush: isManaged = " + em.contains(dataTypes) + " version = " + dataTypes.getEntityVersion() + " aString = " + dataTypes.getAString()); em.clear(); System.out.println("3. ***** After clear: isManaged = " + em.contains(dataTypes) + " version = " + dataTypes.getEntityVersion() + " aString = " + dataTypes.getAString()); dataTypes = (DataTypes)em.find(DataTypesDAO.class, dataTypes.getEntityId()); System.out.println("4. ***** After find by PK: isManaged = " + em.contains(dataTypes) + " version = " + dataTypes.getEntityVersion() + " aString = " + dataTypes.getAString()); ut.commit(); ut = getTransaction(); ut.begin(); em = getEntityManager(); dataTypes = (DataTypes)em.find(DataTypesDAO.class, dataTypes.getEntityId()); System.out.println("5. ***** After find by PK: isManaged = " + em.contains(dataTypes) + " version = " + dataTypes.getEntityVersion() + " aString = " + dataTypes.getAString()); ut.commit(); 1. ***** Before merge: isManaged = false version = 7 aString = 888 2. ***** After flush: isManaged = true version = 8 aString = 999 3. ***** After clear: isManaged = false version = 8 aString = 999 4. ***** After find by PK: isManaged = true version = 7 aString = 888 5. ***** After find by PK: isManaged = true version = 8 aString = 999 Reproducible: Always Steps to Reproduce: 1. See test code in Details section