Here's some code that reproduces my problem. Before the code, I think it's interesting to note that I started making this example in JPA (because I had an old test that used JPA) and I was not able to reproduce the error. However, after converting to JDO, I get the error. I'm not 100% sure the code is exactly the same, however, but wanted to note it in case it's helpful to anyone.
LocalServiceTestCase is based on the examples from Google. Does anyone see a problem with the code or is this a legit bug? @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") public class ParentOfOne { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private SharedChild child; ... } @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") public class ParentOfList { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private List<SharedChild> children; ... } @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") public class SharedChild { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key id; @Persistent private String name; ... } public class SharedChildTestCase extends LocalServiceTestCase { private PersistenceManager persistenceManager; @Before public void openPersistenceManager() { PersistenceManagerFactory persistenceManagerFactory = JDOHelper .getPersistenceManagerFactory("transactions-optional"); persistenceManager = persistenceManagerFactory.getPersistenceManager (); } @After public void closePersitenceManager() { persistenceManager.close(); } @Test public void saveParents() { ParentOfList pol = new ParentOfList(); List<SharedChild> list = new ArrayList<SharedChild>(); SharedChild c1 = new SharedChild(); c1.setName("c1"); list.add(c1); SharedChild c2 = new SharedChild(); c2.setName("c2"); list.add(c2); pol.setChildren(list); persistenceManager.makePersistent(pol); ParentOfOne poo = new ParentOfOne(); SharedChild c3 = new SharedChild(); c1.setName("c3"); poo.setChild(c3); persistenceManager.makePersistent(poo); } } On Sep 22, 9:40 am, objectuser <kevin.k.le...@gmail.com> wrote: > Thanks, Marton. That's very unfortunate. The limitations still > surprise me. Is that documented somewhere? Need to go back and > reread that stuff I guess. > > I'll see if I can come up with a simple test case for the collection. > > On Sep 22, 3:28 am, Marton Papp <mapr...@gmail.com> wrote: > > > A class cannot have two different owned relationship to a single > > class. For example if I have these two classes: > > > @PersistenceCapable(identityType = IdentityType.APPLICATION) > > public class Parent3 { > > > @PrimaryKey > > @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > > private Long id; > > > Child1 child1; > > > Child1 child2; > > > // ... get-set > > > } > > > @PersistenceCapable(identityType = IdentityType.APPLICATION) > > public class Child1 { > > > @PrimaryKey > > @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > > private Key id; > > > // ... get-set > > > } > > > then this code will fail with an assertion error: > > > public void testMultiParent2() throws Exception { > > > PersistenceManager pm; > > > Parent3 p3 = null; > > Parent3 p3Loaded = null; > > > pm = pmf.getPersistenceManager(); > > pm.currentTransaction().begin(); > > > p3 = new Parent3(); > > p3.setChild1(new Child1()); > > p3.setChild2(new Child1()); > > pm.makePersistent(p3); > > pm.currentTransaction().commit(); > > pm.close(); > > > pm = pmf.getPersistenceManager(); > > pm.currentTransaction().begin(); > > > p3Loaded = pm.getObjectById(Parent3.class, p3.getId()); > > > Assert.assertNotSame(p3Loaded.getChild1(), > > p3Loaded.getChild2()); > > > pm.currentTransaction().commit(); > > pm.close(); > > > } > > > It is because the datastore represents the relationship between Child1 > > and Parent3 instances by making the Parent3 instance the parent of the > > Child1 instance. And it does the same for both Parent3.child1 and > > Parent3.child2 relationships, so there is no way to tell which > > property a particular instance of Child1 has been assigned to > > originally. > > > I could not reproduce your problem with the list of children. Could > > you send some code that fails for you? > > > Marton > > > On Sep 22, 3:31 am, objectuser <kevin.k.le...@gmail.com> wrote: > > > > After some more testing this is what I observe: > > > - If A has one C property and B has two C properties, I can save both > > > the A and the B instances, when I get the B instance, both C > > > properties point to the same instance of C. > > > - If A has one C property and B has a property that is a List of Cs, I > > > get the exception in my original post. > > > > I guess I need to work this down to a repeatable example and file a > > > defect report. > > > > On Sep 21, 2:49 pm, objectuser <kevin.k.le...@gmail.com> wrote: > > > > > I'll let leszek talk more about the code, but I assumed that the > > > > commented out line was just testing both scenarios. In the scenario > > > > without comment on the line, it would be my scenario: the same "owned > > > > type" but not the same "owned instance". > > > > > My original question is not about one particular entity having two > > > > parents (in an owned relationship), but having two entity groups share > > > > the same "owned" Java type. > > > > > Does that make sense? > > > > > On Sep 21, 2:00 pm, Marton Papp <mapr...@gmail.com> wrote: > > > > > > Hi, > > > > > > The code in that form also works for me, but just because the > > > > > exception is caught and never reported. If you rethrow any exceptions > > > > > from the catch blocks than you should get something like the > > > > > following: > > > > > > Detected attempt to establish Parent2(3) as the parent of Parent1(1)/ > > > > > Child1(2) but the entity identified by Parent1(1)/Child1(2) is already > > > > > a child of Parent1(1). A parent cannot be established or changed once > > > > > an object has been persisted. > > > > > org.datanucleus.exceptions.NucleusUserException: Detected attempt to > > > > > establish Parent2(3) as the parent of Parent1(1)/Child1(2) but the > > > > > entity identified by Parent1(1)/Child1(2) is already a child of > > > > > Parent1 > > > > > (1). A parent cannot be established or changed once an object has > > > > > been persisted. > > > > > at > > > > > org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch > > > > > (DatastoreRelationFieldManager.java:214) > > > > > at > > > > > org.datanucleus.store.appengine.DatastoreRelationFieldManager > > > > > $1.setObjectViaMapping(DatastoreRelationFieldManager.java:129) > > > > > at > > > > > org.datanucleus.store.appengine.DatastoreRelationFieldManager > > > > > $1.apply(DatastoreRelationFieldManager.java:108) > > > > > at > > > > > org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelations > > > > > (DatastoreRelationFieldManager.java:80) > > > > > at > > > > > org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations > > > > > (DatastoreFieldManager.java:795) > > > > > at > > > > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProcess > > > > > (DatastorePersistenceHandler.java:288) > > > > > at > > > > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects > > > > > (DatastorePersistenceHandler.java:241) > > > > > at > > > > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject > > > > > (DatastorePersistenceHandler.java:225) > > > > > at > > > > > org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent > > > > > (JDOStateManagerImpl.java:3185) > > > > > at org.datanucleus.state.JDOStateManagerImpl.makePersistent > > > > > (JDOStateManagerImpl.java:3161) > > > > > at org.datanucleus.ObjectManagerImpl.persistObjectInternal > > > > > (ObjectManagerImpl.java:1298) > > > > > at org.datanucleus.ObjectManagerImpl.persistObject > > > > > (ObjectManagerImpl.java:1175) > > > > > at org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent > > > > > (JDOPersistenceManager.java:669) > > > > > at org.datanucleus.jdo.JDOPersistenceManager.makePersistent > > > > > (JDOPersistenceManager.java:694) > > > > > at > > > > > hu.mapro.gae.test.forum.TestForum.testMultiParent(TestForum.java: > > > > > 44) > > > > > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > > > > > at sun.reflect.NativeMethodAccessorImpl.invoke > > > > > (NativeMethodAccessorImpl.java:39) > > > > > at sun.reflect.DelegatingMethodAccessorImpl.invoke > > > > > (DelegatingMethodAccessorImpl.java:25) > > > > > at java.lang.reflect.Method.invoke(Method.java:597) > > > > > at > > > > > org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59) > > > > > at org.junit.internal.runners.MethodRoadie.runTestMethod > > > > > (MethodRoadie.java:98) > > > > > at > > > > > org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java: > > > > > 79) > > > > > at > > > > > org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters > > > > > (MethodRoadie.java:87) > > > > > at > > > > > org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java: > > > > > 77) > > > > > at > > > > > org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42) > > > > > at > > > > > org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod > > > > > (JUnit4ClassRunner.java:88) > > > > > at org.junit.internal.runners.JUnit4ClassRunner.runMethods > > > > > (JUnit4ClassRunner.java:51) > > > > > at org.junit.internal.runners.JUnit4ClassRunner$1.run > > > > > (JUnit4ClassRunner.java:44) > > > > > at org.junit.internal.runners.ClassRoadie.runUnprotected > > > > > (ClassRoadie.java:27) > > > > > at org.junit.internal.runners.ClassRoadie.runProtected > > > > > (ClassRoadie.java:37) > > > > > at org.junit.internal.runners.JUnit4ClassRunner.run > > > > > (JUnit4ClassRunner.java:42) > > > > > at > > > > > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run > > > > > (JUnit4TestReference.java:46) > > > > > at org.eclipse.jdt.internal.junit.runner.TestExecution.run > > > > > (TestExecution.java:38) > > > > > at > > > > > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests > > > > > (RemoteTestRunner.java:467) > > > > > at > > > > > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests > > > > > (RemoteTestRunner.java:683) > > > > > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run > > > > > (RemoteTestRunner.java:390) > > > > > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main > > > > > (RemoteTestRunner.java:197) > > > > > > The error message is self-explanatory. According to my knowledge it is > > > > > impossible for a single entity to have multiple parents, just as it is > > > > > impossible to change the parent of an entity (or any other part of its > > > > > primary key). > > > > > > But you were talking about a "class" being in owned realationship with > > > > > two different classes, not an "entity". If I remove the comment from > > > > > the code above that creates a new child entity before assigning it to > > > > > the second parent instance then it is working as expected. Of course > > > > > they will be two different employee instances with different parents > > > > > (of different types). > > > > > > Marton > > > > > > On Sep 21, 4:49 pm, leszek <leszek.ptokar...@gmail.com> wrote: > > > > > > > That's very interesting because it > > ... > > read more » --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to google-appengine-java@googlegroups.com To unsubscribe from this group, send email to google-appengine-java+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en -~----------~----~----~----~------~----~------~--~---