代码之家  ›  专栏  ›  技术社区  ›  raisercostin

GAE JDO与双向导航保持一对多自有关系

  •  5
  • raisercostin  · 技术社区  · 15 年前

    我尝试使用JDO在GAE中保持一对多的双向导航关系。

    我手动添加 Contact User 最后,我希望 接触 将引用父级 用户 对象。

    • 如果在持久化父级之前手动配置此项,我将获得 例外: org.datanucleus.store.appengine.DatastoreRelationFieldManager.checkForParentSwitch(DatastoreRelationFieldManager.java:204)
    • 用户 对象持久性父引用不是 更新。
    • 接触 对象是从 使用键的数据存储父引用未更新。

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

    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;
        }
    }
    
    2 回复  |  直到 10 年前
        1
  •  7
  •   Dmitry    15 年前

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

    你也可以阅读 Max Ross's article 或者看看 my code 从从查询中提取的子对象(消息)访问父对象(讨论)

        2
  •  0
  •   Tom    14 年前

    只需将代码与所指出的更正dmitry一起发布,以便于阅读:

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