2009-12-28 15 views
5

Sto cercando di mantenere una relazione di proprietà uno-a-molti con navigazione bidirezionale in GAE usando JDO.Mantenimento di Gae Jdo sulla relazione uno-a-molti con navigazione bidirezionale

ho aggiungere manualmente la classe Contact a User, e mi aspetto che alla fine il Contact avrà un riferimento al genitore User oggetto.

  • Se devo configurare manualmente prima che io insisto il genitore, ottengo un un'eccezione: org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
  • Dopo la persistenza User oggetto il riferimento principale non viene aggiornato.
  • Dopo che l'oggetto Contact viene recuperato dal datastore usando la chiave del genitore di riferimento non viene aggiornato.

non capisco dove il mio errore è.

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; 
    } 
} 

risposta

7

Secondo App Engine docs, è necessario specificare "mappedBy" nel proprietario del vostro rapporto.

Si consiglia inoltre di leggere Max Ross's article o di avere uno sguardo a my code che accede genitore (Discussione) da un oggetto figlio (messaggio), che vengono recuperati da una query

+0

Anzi ho dimenticato di aggiungere un mappedBy per User.contacts campo @Persistent(mappedBy="user") public List contacts = new ArrayList(); raisercostin

0

Basta inviare il codice con la correzione Dmitry ha sottolineato fuori per una più facile lettura:

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

Commento di utente senza privilegi di commento ([profilo] (http://stackoverflow.com/users/579750/)): 'dipendente' è per proprietà, per la raccolta di proprietà, usare 'dependeElement'. – Anne