2009-12-28 7 views
5

Estoy tratando de mantener una relación de uno a muchos con navegación bidireccional en GAE usando JDO.Persistencia de Gae Jdo en la relación propiedad uno-a-muchos con navegación bidireccional

que añadir manualmente la clase Contact a User, y yo esperaría que al final el Contact tendrá una referencia al padre User objeto.

  • Si puedo configurar manualmente antes de que persisten los padres, me sale un excepción: org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
  • Después de la persistencia User objeto la referencia padre no se actualiza.
  • Después de recuperar el objeto Contact desde el almacén de datos utilizando la clave, no se actualiza la referencia principal.

No entiendo dónde está mi error.

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

Respuesta

7

Según App Engine docs, debería especificar "mappedBy" en el dueño de su relación.

También puede leer Max Ross's article o para echar un vistazo a my code que accede a los padres (Discusión) a partir de un objeto secundario (Mensaje), que se obtiene de una consulta

+0

de hecho me olvidó añadir un mappedBy a User.contacts campo @Persistent(mappedBy="user") public List contacts = new ArrayList(); raisercostin

0

Sólo publicar el código con la corrección Dmitry señaló a cabo para facilitar la lectura:

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

comentario de usuario sin privilegios de comentario ([perfil] (http://stackoverflow.com/users/579750/)): 'dependiente' es para la propiedad, para la colección de propiedades, use 'dependeElement'. – Anne

Cuestiones relacionadas