GAE数据存储区:持久引用的对象

时间:2010-06-04 13:38:05

标签: java google-app-engine google-cloud-datastore

我正在尝试将Java对象持久化到GAE数据存储区。

我不确定如何持久化具有(“非平凡”)引用对象的对象。 也就是说,假设我有以下内容。

public class Father {
    String name;
    int age;
    Vector<Child> offsprings; //this is what I call "non-trivial" reference 
    //ctor, getters, setters...
}

public class Child {
    String name;
    int age;
    Father father; //this is what I call "non-trivial" reference 
    //ctor, getters, setters...
}

名称字段在每个类型域中都是唯一的,并被视为主键。

为了保留“普通”(String,int)字段,我只需要添加正确的注释。到现在为止还挺好。 但是,我不明白我应该如何坚持参考的自酿(儿童,父亲)类型。 我应该:

  1. 转换每个此类引用以保存主键(在此示例中为名称字符串)而不是“实际”对象,因此Vector<Child> offsprings;变为Vector<String> offspringsNames;

    如果是case,我如何在运行时处理对象?我是否只是从Class.getName查询主键,以检索refrenced对象?

  2. 转换每个此类引用以保存数据存储区在正确put()操作时提供给我的实际密钥?也就是说,Vector<Child> offsprings;变为Vector<Key> offspringsHashKeys;
  3. 我已阅读所有官方相关的GAE文档/示例。在整个过程中,它们始终保持“琐碎”引用,本地由数据存储区支持(例如,在留言簿示例中,仅限字符串和长整数。)

3 个答案:

答案 0 :(得分:0)

我在我的jappstart项目中使用GAE / JPA创建父/子关系的示例。看看身份验证相关实体如何相互关联here

一对一(参见UserAccount.java和PersistentUser.java):

// parent
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private PersistentUser persistentUser;

// child
@OneToOne(mappedBy = "persistentUser", fetch = FetchType.LAZY)
private UserAccount userAccount;

一对多(参见PersistentUser.java):

@OneToMany(mappedBy = "persistentUser", cascade = CascadeType.ALL)
private Collection<PersistentLogin> persistentLogins;

多对一(参见PersistentLogin.java):

@ManyToOne(fetch = FetchType.LAZY)
private PersistentUser persistentUser;

另外,请注意构造函数中KeyFactory如何用于具有父对象而非父对象的实体。

@Id
private Key key;

// this entity has a parent
public PersistentUser(final Key key, final String username) {
    this.key = KeyFactory.createKey(key, getClass().getSimpleName(), username);
    ...
}

// this entity does not have a parent
public UserAccount(final String username) {
    this.key = KeyFactory.createKey(getClass().getSimpleName(), username);
    ....
}

希望这对你有所帮助。我无法从问题中判断出您使用的是JPA还是JDO。

答案 1 :(得分:0)

如果您在父亲的FatherChild中提到了Child,那么假设父与子之间的关系是假的,那么您可能会出现不一致的情况。双向(即每个Child的父亲应该在该父亲的Child名单中。只需要两个引用中的一个。

两种解决方案都可行,但保留父亲的儿童名单有两个缺点:

  1. 每次访问Father对象都会将列表键下载到子对象。如果有很多密钥,这可能会导致不必要的开销。
  2. 我认为GAE将列表的大小限制为5,000个项目。

答案 2 :(得分:0)

  • 请参阅以下各节中的google appengine docs以获得更清晰的理解(关系,交易)

  • 另请阅读JDO中可拆卸对象

  • 要查询选择性列(或字段),请阅读JDO中的fetchgroups

对于您的问题您有几种选择:

  • 拥有一对多关系(对象将在同一个实体组中)在这里,您可以在父级(父级)中拥有一个Child列表。这会将所有对象放在同一个实体组中。如果您不想在每次获取父级时获取子项,则可以从“默认获取组”中删除子项

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Father {
   @PrimaryKey
   @Persistent
   private String name;

   @Persistent
   private int age;

   @Persistent(mappedBy = "father", defaultFetchGroup = "false")
   private List childern;
}

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Child   {
   @Persistent
   @PrimaryKey
   private String name;

   @Persistent
   private Father dad;
}

  • 存储密钥而不是引用的无关关系:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Father {

   @PrimaryKey
   @Persistent
   private String name;

   @Persistent
   private int age;

   @Persistent
   private List childern;
}

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Child   {
   @Persistent
   @PrimaryKey
   private String name;

   @Persistent
   private Key dad;
}

在这种情况下,您必须管理参照完整性,并确保它们在同一实体组中,如果您必须在单个事务中更新/添加它们

国际海事组织,如果我在模拟真实世界(父亲 - 孩子)的情景,我会选择“拥有的关系”路线,因为,真的,一个人可以拥有多少个孩子;)。当然还有一个问题,即你一次要更新多少父亲?

希望这有帮助,欢呼!