Community
Participate
Working Groups
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.
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.
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.
the test cases are i the testing project at the same level as employee.xml
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.
Created attachment 173704 [details] suggested patch The fix + some tests + fixed employee.xml example.
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
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.
Checked into trunk, 2.1.1 is pending.
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).
Backported to 2.1.1.
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink