Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 316242 - CopyGroup.CASCADE_TREE does not reset PK values on nested entities
Summary: CopyGroup.CASCADE_TREE does not reset PK values on nested entities
Status: CLOSED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P2 normal (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-06-09 01:55 EDT by Doug Clarke CLA
Modified: 2022-06-09 10:22 EDT (History)
3 users (show)

See Also:


Attachments
2.1 test workaround patch (3.41 KB, patch)
2010-06-10 18:25 EDT, Andrei Ilitchev CLA
no flags Details | Diff
suggested patch (4.89 KB, patch)
2010-07-07 15:51 EDT, Andrei Ilitchev CLA
no flags Details | Diff
additional patch (24.02 KB, patch)
2010-07-09 16:18 EDT, Andrei Ilitchev CLA
no flags Details | Diff
test patch (3.24 KB, patch)
2010-07-14 16:11 EDT, Andrei Ilitchev CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Doug Clarke CLA 2010-06-09 01:55:08 EDT
When executing the following example to copy and entity and persist the new graph:

        CopyGroup group = new CopyGroup();
        group.setShouldResetPrimaryKey(true);
        group.setShouldResetVersion(true);
        group.cascadeTree(); // Copy only the attributes specified
        group.addAttribute(Employee_.firstName.getName());
        group.addAttribute(Employee_.lastName.getName());
        group.addAttribute(Employee_.gender.getName());
        group.addAttribute(Employee_.period.getName());
        group.addAttribute(Employee_.salary.getName());
        group.addAttribute(Employee_.address.getName());
        group.addAttribute(Employee_.phoneNumbers.getName());
        
        Employee empCopy = (Employee) em.unwrap(JpaEntityManager.class).copy(emp, group);
        System.out.println(">>> Employee copied");
        
        // Persist the employee copy
        em.persist(empCopy);
        System.out.println(">>> Persist new entity complete");

        // Flush the changes to the database
        em.flush();

The resulting empCopy has an address with its id set to the same as the original which causes a PK collision when attempting to insert the new address.

When I force the empCopy.getAddress().setId(0) I then get a stack overflow error on the manager relationshiop during the flush. I have not been able to diagnose where this secondary error is coming form.
Comment 1 Andrei Ilitchev CLA 2010-06-09 17:00:42 EDT
Partialy fixed in both trunk and 2.1

There is still a problem in case CopyGroup has a leaf relation attribute, such as group.addAttribute("address");
That will be fixed in trunk soon, but too late for 2.1.

Otherwise it should work now. 
Note that in case of PhoneNumber that has pk{owner, type} even with setShouldResetPrimaryKey flag set the relational part of the pk (owner) is still copied. For persist to work another part of the pk (type) should be either set on the copied object(s) or attribute "phoneNumbers.type" should be added to the group.
Comment 2 Doug Clarke CLA 2010-06-10 02:45:16 EDT
I have updated the employee.xml example in the 2.1 branch

http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/branches/2.1/trunk/examples/jpa.employee/eclipselink.example.jpa.employee.xml/

If you look at the mappings you'll see that I have mapped PhoneNumber with its own unique sequence generated id

http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/branches/2.1/trunk/examples/jpa.employee/eclipselink.example.jpa.employee.xml/src/META-INF/eclipselink-orm.xml

Please also look at the Transactions example @ http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/branches/2.1/trunk/examples/jpa.employee/eclipselink.example.jpa.employee.xml/src/example/Transactions.java

    /**
     * Create a new Employee entity by cloning an existing one using CopyGroup
     * with {@link JpaEntityManager#copy(Object, AttributeGroup)}
     */
    public Employee cloneEmployeeUsingCopy(EntityManager em) {
        // Search for an Employee with an Address and Phone Numbers
        TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e WHERE e.id IN (SELECT MIN(ee.id) FROM Employee ee)", Employee.class);

        Employee emp = query.getSingleResult();

        System.out.println(">>> Employee retrieved");

        // Copy only its names and phone Numbers
        CopyGroup group = new CopyGroup();
        group.setShouldResetPrimaryKey(true);
        group.setShouldResetVersion(true);
        group.cascadeTree(); // use the attributes specified
        // Add attributes using canonical metamodel
        group.addAttribute(Employee_.firstName.getName());
        group.addAttribute(Employee_.lastName.getName());
        group.addAttribute(Employee_.gender.getName());
        group.addAttribute(Employee_.salary.getName());
        group.addAttribute(Employee_.startTime.getName());
        group.addAttribute(Employee_.endTime.getName());
        group.addAttribute(Employee_.period.getName());
        group.addAttribute(Employee_.responsibilities.getName());
        group.addAttribute(Employee_.address.getName());
        group.addAttribute(Employee_.phoneNumbers.getName());

        Employee empCopy = (Employee) em.unwrap(JpaEntityManager.class).copy(emp, group);
        
        for (PhoneNumber phone: empCopy.getPhoneNumbers()) {
            phone.setId(0);
        }
        
        em.persist(empCopy);
        
        em.flush();

        return empCopy;
    }


This is tested and verified by testing.TransactionTests.cloneEmployeeUsingCopy. 

ISSUE: The Address now gets inserted with the newly assigned sequence number but the PhoneNumber instance in the collection has the same id as the original. You will note in the Transactions example I iterate over the phone numbers setting each id to zero prior to performing the em.persist. With this work-around the example passes.
Comment 3 Doug Clarke CLA 2010-06-10 02:53:02 EDT
the test cases are i the testing project at the same level as employee.xml
Comment 4 Andrei Ilitchev CLA 2010-06-10 18:25:04 EDT
Created attachment 171676 [details]
2.1 test workaround patch

As I've already mentioned before, in 2.1 there is a bug - a reference "leaf" mapping (such as "phoneNumbers") doesn't work correctly with copy (the trivial fix will be merged into 2.1.1 shortly).
Even more specifically - the problem occurs in case the reference descriptor has at least one reference mapping outside of its primary key.

The PhoneNumber now is that kind of class - owner is a reference mapping outside of the primary key.
The workaround is to provide the "full" group - the one that contains all attributes - this workaround is in the patch.

BTW, the "traditional" PhoneNumber - with pk = {owner, type} should work without the workarond.
Comment 5 Andrei Ilitchev CLA 2010-07-07 15:51:25 EDT
Created attachment 173704 [details]
suggested patch

The fix + some tests + fixed employee.xml example.
Comment 6 Andrei Ilitchev CLA 2010-07-07 17:01:26 EDT
Checked the fix into trunk, 2.1.1 is pending.

Also fixed Bug 316242 - CopyGroup.CASCADE_TREE does not reset PK values on nested entities.

In both SimpleSerializeFetchGroupTests and fieldaccess.SimpleSerializeFetchGroupTests added
copyWithPk and copyWithoutPk for this bug;
copyCascadePrivateParts for bug 316241.

Also fixed TransactionTests in examples/jpa.employee/eclipselink.example.jpa.employee.testing
Comment 7 Andrei Ilitchev CLA 2010-07-09 16:18:05 EDT
Created attachment 173912 [details]
additional patch

CopyPolicy.CASCADE_TREE value is changed (the former value was the same as CASCADE_ALL_PARTS);
Added tests for cascade depth NO_CASCADE, CASCADE_PRIVATE_PARTS, CASCADE_ALL_PARTS to both org.eclipse.persistence.testing.tests.jpa.fetchgroups.SimpleSerializeFetchGroupTests and
org.eclipse.persistence.testing.tests.jpa.fieldaccess.fetchgroups.SimpleSerializeFetchGroupTests

However in fieldaccess case had to comment out CASCADE_ALL_PARTS test because of Bug 319426 - Original and copy share ValueHolder.
Comment 8 Andrei Ilitchev CLA 2010-07-09 16:23:17 EDT
Checked into trunk, 2.1.1 is pending.
Comment 9 Andrei Ilitchev CLA 2010-07-14 16:11:07 EDT
Created attachment 174336 [details]
test patch

A small change to tests to ensure that the object is always altered as intended (upparently some time the originl value of PhoneNumber's area code could be exactly the same as the new one - therefore no expected update sql happened and test failed).
Comment 10 Andrei Ilitchev CLA 2010-07-14 16:14:06 EDT
Checked into trunk, 2.1.1 is pending.
Comment 11 Andrei Ilitchev CLA 2010-07-15 12:20:16 EDT
Backported to 2.1.1.
Comment 12 Eclipse Webmaster CLA 2022-06-09 10:22:10 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink