2009-12-28 96 views
5

我试图坚持使用JDO在GAE中双向导航的一对多拥有关系。Gae Jdo坚持一对多拥有双向导航的关系

我手动添加ContactUser类,而我预计,在年底的Contact将不得不父User对象的引用。

  • 如果我配置此之前手动坚持我父母,我得到一个 例外:org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
  • User对象持久化父参考不 更新后。
  • 使用密钥从 数据存储中检索到Contact对象之后,父引用不会更新。

我不明白我的错误在哪里。

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

回答

7

根据App Engine docs,您应该在关系所有者中指定“mappedBy”。

您可能还需要阅读Max Ross's article或看看my code从一个子对象(消息),这是从查询

+0

事实上,我忘了添加的mappedBy到User.contacts场 @Persistent(mappedBy="user") public List contacts = new ArrayList(); raisercostin 2009-12-30 14:52:18

0

刚刚发布与修正梅德指出代码获取访问父(讨论)出来以方便您阅读:

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

评论用户不加评论权限([资料](http://stackoverflow.com/users/579750/ )):“依赖”是属性,为了收集属性,使用'dependeElement'。 – Anne 2011-12-01 20:39:31