Community
Participate
Working Groups
To reproduce need a class model with private ownership in the base class and at least two level inheritance. Class A privately owns D (ToOne or ToMany); Class B inherits from A; Class C inherit from B. To reproduce: Setup: create and instance of C that has an instance of D; Test: remove the instance of D from its owner C, commit. Result: The instance of D is still around - both in the shared cache and in the database. Expected result: As a privately owned object removed from its master the instance of D should have been deleted.
The problem is in InheritancePolicy.postInitialize method: its called for a child before being called for its parent. Therefore all the following three assignments fail for C: if (parent.hasPreDeleteMappings()) { getDescriptor().getPreDeleteMappings().addAll(parent.getPreDeleteMappings()); } if (parent.hasMappingsPostCalculateChanges()) { getDescriptor().getMappingsPostCalculateChanges().addAll(parent.getMappingsPostCalculateChanges()); } if (parent.hasMappingsPostCalculateChangesOnDeleted()) { getDescriptor().getMappingsPostCalculateChangesOnDeleted().addAll(parent.getMappingsPostCalculateChangesOnDeleted()); } When they are called for C, they copy settings from B - but nothing yet set on B. Next the method is called for B - and the settings are copied from A to B ok - but they never copied to C. It's getMappingsPostCalculateChanges that's responsible for the bug, however all three should be assignments should be fixed - they should be performed in "top - down" order (parent first, then child). Workaround: public void postLogin(SessionEvent event) { Session session = event.getSession(); Collection<ClassDescriptor> descriptors = session.getDescriptors().values(); for (ClassDescriptor descriptor : descriptors) { // process descriptors for base classes if (descriptor.hasInheritance() && !descriptor.getInheritancePolicy().isChildDescriptor()) { copyToChildren(descriptor); } } } public static void copyToChildren(ClassDescriptor parentDescriptor) { List<ClassDescriptor> childDescriptors = parentDescriptor.getInheritancePolicy().getChildDescriptors(); if (childDescriptors != null) { for (ClassDescriptor childDescriptor : childDescriptors) { if (parentDescriptor.hasPreDeleteMappings()) { for (DatabaseMapping mapping : parentDescriptor.getPreDeleteMappings()) { if (!childDescriptor.getPreDeleteMappings().contains(mapping)) { childDescriptor.getPreDeleteMappings().add(mapping); } } } if (parentDescriptor.hasMappingsPostCalculateChanges()) { for (DatabaseMapping mapping : parentDescriptor.getMappingsPostCalculateChanges()) { if (!childDescriptor.getMappingsPostCalculateChanges().contains(mapping)) { childDescriptor.getMappingsPostCalculateChanges().add(mapping); } } } if (parentDescriptor.hasMappingsPostCalculateChangesOnDeleted()) { for (DatabaseMapping mapping : parentDescriptor.getMappingsPostCalculateChangesOnDeleted()) { if (!childDescriptor.getMappingsPostCalculateChangesOnDeleted().contains(mapping)) { childDescriptor.getMappingsPostCalculateChangesOnDeleted().add(mapping); } } } copyToChildren(childDescriptor); } } }
Created attachment 199359 [details] Suggested patch. The three assignments are moved from InheritancePolicy.postInitialize to ClassDescriptor.initialize method (those are called for parent first, then for child). RemovePrivatelyOwnedTestCase is added to InsuranceBasicTestModel (in getDeletePrivateOwnedTestSuite).
Reviewed by Chris. Checked the fix into both 2.3.1 and 2.4.
The workaround provided above is a SessionEventListener - not a session customizer: public class MySessionEventListener extends org.eclipse.persistence.sessions.SessionEventAdaptor { public void postLogin(SessionEvent event) { ... } public static void copyToChildren(ClassDescriptor parentDescriptor) { ... } } SessionEventAdapter should be passed to pu through a property: <property name="eclipselink.session-event-listener" value="MySessionEventListener"/>
*** Bug 354813 has been marked as a duplicate of this bug. ***
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink