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 works for me:
>
> > > > @PersistenceCapable(identityType = IdentityType.APPLICATION)
> > > > public class Employee {
>
> > > >     @PrimaryKey
> > > >     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
> > > >     private Key id;
>
> > > >     private String firstName;
>
> > > >     private String lastName;
>
> > > > }
>
> > > > @PersistenceCapable(identityType = IdentityType.APPLICATION)
> > > > public class A (B) {
>
> > > >     public Long getId() {
> > > >                 return id;
> > > >         }
>
> > > >         public void setId(Long id) {
> > > >                 this.id = id;
> > > >         }
>
> > > >         public Employee getE() {
> > > >                 return e;
> > > >         }
>
> > > >         public void setE(Employee e) {
> > > >                 this.e = e;
> > > >         }
>
> > > >         @PrimaryKey
> > > >     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
> > > >     private Long id;
>
> > > > }
>
> > > > ========================
> > > > (regardless if transaction is used or not - simply makePersistent
> > > > without transaction)
>
> > > >                 PersistenceManager em = 
> > > > EMF.get().getPersistenceManager();
> > > >                 Employee e = null;
> > > >                 try {
> > > >                         em.currentTransaction().begin();
> > > >                 A a = new A();
> > > >                 e = new Employee();
> > > >                 a.setE(e);
> > > >                 em.makePersistent(a);
> > > >                 em.currentTransaction().commit();
> > > >                 } catch (Exception ee) {
> > > >                         em.currentTransaction().rollback();
> > > >                 }
>
> > > >                 try {
> > > >                         em.currentTransaction().begin();
> > > >                 B b = new B();
> > > > //              e = new Employee();
> > > >                 b.setE(e);
> > > >                 em.makePersistent(b);
> > > >                 em.currentTransaction().commit();
> > > >                 } catch (Exception ee) {
> > > >                         em.currentTransaction().rollback();
> > > >                 }
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to