2009-12-28 8 views
5

Ich versuche, eine One-to-many-Beziehung mit bidirektionaler Navigation in GAE mit JDO zu beharren.Gae Jdo beharrt auf One-to-Many-Beziehung mit bidirektionaler Navigation

ich die Contact zu User Klasse manuell hinzufügen, und ich würde erwarten, dass die Contact am Ende einen Verweis auf das übergeordnete Objekt User haben.

  • Wenn ich dies manuell konfigurieren, bevor ich die Eltern beharren, erhalte ich eine Ausnahme: org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
  • Nach dem User Objekt-Persistenz der übergeordnete Referenz nicht aktualisiert wird.
  • Nachdem das Objekt Contact mit Hilfe des Schlüssels aus dem Datenspeicher abgerufen wurde, wird die übergeordnete Referenz nicht aktualisiert.

Ich verstehe nicht, wo mein Fehler ist.

package test; 

import java.util.ArrayList; 
import java.util.List; 
import javax.jdo.PersistenceManager; 
import javax.jdo.PersistenceManagerFactory; 
import javax.jdo.annotations.IdGeneratorStrategy; 
import javax.jdo.annotations.IdentityType; 
import javax.jdo.annotations.PersistenceCapable; 
import javax.jdo.annotations.Persistent; 
import javax.jdo.annotations.PrimaryKey; 
import org.junit.Assert; 
import org.junit.Test; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import com.google.appengine.api.datastore.Key; 

public class DatastoreJdoTest extends LocalServiceTestCase { 
    @Autowired 
    @Qualifier("persistenceManagerFactory") 
    PersistenceManagerFactory pmf; 

    @Test 
    public void testBatchInsert() { 
     Key contactKey; 
     PersistenceManager pm = pmf.getPersistenceManager(); 
     try { 
      pm.currentTransaction().begin(); 
      User user = new User(); 
      Contact contact = new Contact("contact1"); 
      user.contacts.add(contact); 

      /* 
      * With this an exception is thrown 
      * 
      * Detected attempt to establish User(1)/Contact(2) as the parent of 
      * User(1) but the entity identified by User(1) has already been 
      * persisted without a parent. A parent cannot be established or 
      * changed once an object has been persisted. 
      * org.datanucleus.store.appengine.FatalNucleusUserException: 
      * Detected attempt to establish User(1)/Contact(2) as the parent of 
      * User(1) but the entity identified by User(1) has already been 
      * persisted without a parent. A parent cannot be established or 
      * changed once an object has been persisted. at 
      * org.datanucleus.store 
      * .appengine.DatastoreRelationFieldManager.checkForParentSwitch 
      * (DatastoreRelationFieldManager.java:204) 
      */ 
      //contact.user = user; 
      Assert.assertNull(contact.key); 
      pm.makePersistent(user); 
      Assert.assertNotNull(contact.key); 

      pm.currentTransaction().commit(); 

      contactKey = contact.key; 
      //this assertion is broken. why ? 
      //Assert.assertNotNull(contact.user); 
     } finally { 
      if (pm.currentTransaction().isActive()) { 
       pm.currentTransaction().rollback(); 
      } 
     } 
     Contact contact2 = pm.getObjectById(Contact.class, contactKey); 
     Assert.assertNotNull(contact2); 
     //this assertion is broken. why the contact don't store the parent user ? 
     Assert.assertNotNull(contact2.user); 
    } 
} 

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") 
class User { 
    @PrimaryKey 
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
    public Key key; 
    @Persistent 
    public String name; 
    @Persistent 
    public List<Contact> contacts = new ArrayList<Contact>(); 
} 

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") 
class Contact { 
    @PrimaryKey 
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
    Key key; 
    @Persistent 
    public String contact; 
    @Persistent(mappedBy = "contacts", dependent = "true") 
    public User user; 

    public Contact(String contact) { 
     this.contact = contact; 
    } 
} 

Antwort

7

Nach App Engine docs, sollten Sie "mappedBy" in dem Vermieter Ihrer Beziehung angeben.

Sie auch Max Ross's article oder haben einen Blick auf my code lesen möchten, die Eltern (Diskussion) von einem untergeordneten Objekt (Message), die

+0

der Tat habe ich vergessen, ein mappedBy hinzufügen Feld durch Benutzer ohne Kommentar Privilegien @Persistent(mappedBy="user") public List contacts = new ArrayList(); raisercostin

0

gerade von einer Abfrage abgerufen wird Zugriff auf den Code mit der Korrektur Dmitry wies Posting out für das Lesen zu vereinfachen:

import java.util.ArrayList; 
import java.util.List; 
import javax.jdo.PersistenceManager; 
import javax.jdo.PersistenceManagerFactory; 
import javax.jdo.annotations.IdGeneratorStrategy; 
import javax.jdo.annotations.IdentityType; 
import javax.jdo.annotations.PersistenceCapable; 
import javax.jdo.annotations.Persistent; 
import javax.jdo.annotations.PrimaryKey; 
import org.junit.Assert; 
import org.junit.Test; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import com.google.appengine.api.datastore.Key; 

public class DatastoreJdoTest extends LocalServiceTestCase { 
@Autowired 
@Qualifier("persistenceManagerFactory") 
PersistenceManagerFactory pmf; 

@Test 
public void testBatchInsert() { 
    Key contactKey; 
    PersistenceManager pm = pmf.getPersistenceManager(); 
    try { 
    pm.currentTransaction().begin(); 
    User user = new User(); 
    Contact contact = new Contact("contact1"); 
    user.contacts.add(contact); 

    /* 
    * With this an exception is thrown 
    * 
    * Detected attempt to establish User(1)/Contact(2) as the parent of 
    * User(1) but the entity identified by User(1) has already been 
    * persisted without a parent. A parent cannot be established or 
    * changed once an object has been persisted. 
    * org.datanucleus.store.appengine.FatalNucleusUserException: 
    * Detected attempt to establish User(1)/Contact(2) as the parent of 
    * User(1) but the entity identified by User(1) has already been 
    * persisted without a parent. A parent cannot be established or 
    * changed once an object has been persisted. at 
    * org.datanucleus.store 
    * .appengine.DatastoreRelationFieldManager.checkForParentSwitch 
    * (DatastoreRelationFieldManager.java:204) 
    */ 
    //contact.user = user; 
    Assert.assertNull(contact.key); 
    pm.makePersistent(user); 
    Assert.assertNotNull(contact.key); 

    pm.currentTransaction().commit(); 

    contactKey = contact.key; 
    //this assertion is broken. why ? 
    //Assert.assertNotNull(contact.user); 
    } finally { 
    if (pm.currentTransaction().isActive()) { 
    pm.currentTransaction().rollback(); 
    } 
    } 
    Contact contact2 = pm.getObjectById(Contact.class, contactKey); 
    Assert.assertNotNull(contact2); 
    //this assertion is broken. why the contact don't store the parent user ? 
    Assert.assertNotNull(contact2.user); 
} 
} 

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") 
class User { 
@PrimaryKey 
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
public Key key; 
@Persistent 
public String name; 
@Persistent(mappedBy = "user", dependent = "true") 
public List<Contact> contacts = new ArrayList<Contact>(); 
} 

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true") 
class Contact { 
@PrimaryKey 
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) 
Key key; 
@Persistent 
public String contact; 
@Persistent 
public User user; 

public Contact(String contact) { 
    this.contact = contact; 
} 
} 
+0

Kommentar User.contacts ([Profil] (http://stackoverflow.com/users/579750/)): "abhängig" ist für Eigenschaft, für die Sammlung von Eigenschaften, verwenden Sie 'abhängigeElement'. – Anne