Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 335322 - AttributeChangeTracking: change events not cleared when refresh is called
Summary: AttributeChangeTracking: change events not cleared when refresh is called
Status: CLOSED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-01-25 09:57 EST by Chris Delahunt CLA
Modified: 2022-06-09 10:19 EDT (History)
2 users (show)

See Also:


Attachments
Proposed fix (10.68 KB, patch)
2011-01-28 14:57 EST, Tom Ware CLA
no flags Details | Diff
Updated fix - 2.2 stream (9.61 KB, patch)
2011-01-28 15:23 EST, Tom Ware CLA
no flags Details | Diff
Updated Patch - 2.2 stream (17.45 KB, patch)
2011-01-31 14:18 EST, Tom Ware CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Delahunt CLA 2011-01-25 09:57:01 EST
AttributeChangeTracking events are not being cleared when em.refresh or a query forcing a refresh is called.  For instance:

Employee emp = em.find(Employee.class, id);
emp.setFirstName("changed!");
em.refresh(emp);
..
em.flush();

after the refresh, emp.getFirstName will show the old string, but "changed!" will be updated in the database on the flush call.  

Worse, if a OneToOne/ManyToOne relationship is nulled out:

Employee emp = em.find(Employee.class, id);
emp.setManager(null);
em.refresh(emp);
..
em.flush();

This results in a NullPointerException on the flush or transaction commit:

 java.lang.NullPointerException
	at org.eclipse.persistence.mappings.ObjectReferenceMapping.update(ObjectReferenceMapping.java:1085)
	at org.eclipse.persistence.mappings.ObjectReferenceMapping.preUpdate(ObjectReferenceMapping.java:590)
	at org.eclipse.persistence.descriptors.DescriptorQueryManager.preUpdate(DescriptorQueryManager.java:1089)
	at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1121)
	at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84)
	at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:291)
	at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
	at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808)
	at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:711)
	at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
	at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2842)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463)
	at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:265)
	at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:128)
	at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3766)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1404)
	at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:616)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1552)
	at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:427)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:743)
Comment 1 Tom Ware CLA 2011-01-28 14:57:12 EST
Actual sequence of steps to see the issue (object uses attribute level change tracking)

Read a
Change a.b
Refresh a
Change a.c
flush
change to a.b is written

The issue here is that the ChangeSet created by Attribute Level Change tracking is also stored as part of the unit of work change set.  The UnitOfWork version of this is not cleared by the refresh.   When the 2nd change is made, we look up the change set in the unit of work and use it.  The change from prior to the refresh is still there.
Comment 2 Tom Ware CLA 2011-01-28 14:57:54 EST
Created attachment 187872 [details]
Proposed fix

Proposed fix clears the ObjectChangeSet when a clear is called for revert
Comment 3 Tom Ware CLA 2011-01-28 15:23:08 EST
Created attachment 187874 [details]
Updated fix - 2.2 stream
Comment 4 Tom Ware CLA 2011-01-31 14:18:42 EST
Created attachment 187997 [details]
Updated Patch - 2.2 stream
Comment 5 Tom Ware CLA 2011-01-31 15:17:09 EST
Changes checked into 2.2 - rev 8906

Code is changed to clear the object change set associated with the AttributeChangeListener prior to nulling it out during a refresh

Added 3 tests to EntityManagerJunitTestSuite

Tested with Core and JPA LRG

Reviewed by Gordon Yorke
Comment 6 Tom Ware CLA 2011-01-31 16:01:28 EST
Checked into trunk
Comment 7 Tom Ware CLA 2011-09-02 12:56:08 EDT
See: Bug 356627 - Backport Bug 335322 - AttributeChangeTracking: change events not cleared when refresh is called to 2.1.
Comment 8 Eclipse Webmaster CLA 2022-06-09 10:19:32 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink