I'm trying to persist a one-to-many owned relationship with bidirectional navigation in GAE using JDO.
I manually add the Contact
to User
class, and I would expect that in the end the Contact
will have a reference to the parent User
object.
org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
User
object persistence the parent reference is not
updated. Contact
object is retrieved from the
datastore using the key the parent reference is not updated.I don't understand where my mistake is.
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;
}
}
According to App Engine docs, you should specify "mappedBy" in the owner of your relationship.
You may also want to read Max Ross's article or to have a look at my code which accesses parent (Discussion) from a child object (Message) which is fetched from a query
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With