在一个查询中保存整个一对多的瞬态对象结构

时间:2016-04-27 03:01:32

标签: google-cloud-datastore objectify

简而言之

我似乎已经多次出现了保存对象的MAJOR反模式。我已经阅读了有限的Objectify文档,似乎找不到合适的模式。

详情

我想要存储多个对象。它们都是短暂的(它们还不存在于数据库中)并且它们具有一对多的关系。我不想在我的层次结构中的每个最后一个对象上坐下来调用ofy()。save()。

在以下示例中,播放器具有卡列表。

我的模特:

@Entity
public class Player {
  @Id private Long id = null;//will be generated

  private List<Ref<Card>> cards = new ArrayList<Ref<Card>>();
  //getters and setters here
}

public class Card{
  @Id private Long id = null;//will be generated

  //lots of other fields and getters and setters here
}

我的操作:

我需要创建一个新的玩家和新卡,玩家可以在他的列表中找到卡片。&#34;

理想解决方案:

我想创建播放器和卡片java对象,设置它们的关系,然后将它们传递给Objectify进行保存。像这样:

Player player = new Player();
Card card = new Card();
player.setPlayer(Ref.create(card));
ofy.save().entity(player).now();

失败。第3行试图创建一个新的参考卡,这是不可能的,因为卡还没有一个ID,一旦它已经存在就会分配给它。似乎我必须永远不要将对象与另一个对象关联,直到已经保存了一个对象。

目前的Crappy解决方案

所以,我的解决方案必须是首先保存卡片,然后将其与播放器关联,然后保存播放器。

Player player = new Player();
Card card = new Card();
ofy().save().entity(card).now();
player.setPlayer(Ref.create(card));
ofy().save().entity(card).now();

这太疯狂了。一开始似乎是合理的,但我的应用程序正在处理更多的关系而不仅仅是这个,并且使用这种模式,我的算法将是一个蜘蛛网,在保存实际上关注的实体之前检查集合中的瞬态对象。 / p>

必须有某种方式告诉Objectify只保存所有儿童/相关实体以及我所要求的实体,并进一步生成必要的ID而不是向我抛出异常。

此外,我还需要这种&#34;递归保存&#34;解决方案,即使我的对象都不是瞬态的(即它们都已经有ID)。我不能浪费我的时间来迭代集合,然后在这些集合中的所有集合中保存所有集合。我需要某种方式告诉Objectify只是保存我刚刚通过你的对象。

我一直在阅读这篇@Load注释,我觉得那里可能有某些东西我不知道......我不知道。需要帮忙。文档很少。

更新的解决方案 对于后代 - 使用allocateId()方法将整个ID生成约束从数据库中分离出来,你得到一个非常干净的模式,特别是如果你这样做: 所有数据库@Entity类都有一个私有构造函数和一个静态公共工厂,用于创建临时对象。此静态工厂方法(createTransient())将始终分配新ID。因此,所有客户端代码都可以使用此方法获取新的临时对象,或者用于获取现有持久化实例的明显客观化负载。简单。完成。可爱。

1 个答案:

答案 0 :(得分:1)

我推荐两件事:

  1. 使用ObjectifyFactory.allocateId()构建对象时手动分配ID。不要使用&#34; save with null autogenerates&#34;特征。正如您所注意到的,它是一个PITA来处理具有空ID的实体对象,因此不允许它们存在。
  2. 使用延期保存。 ofy().defer().save().entity(blah);您可以通过这种方式保存几乎任何数量的内容,并且只有在提交(或关闭客观化会话)时才会保存一次。延迟多次保存在同一实体上只会产生一次保存。
  3. 这种留下ids的模式为null并在保存时填充它是JPA日的延续。它与JPA的合作也不是很好;有很多令人沮丧的边缘案例处理实体缺少id(特别是当你想放入地图或集合时)。最好的解决方案是简单地保证没有实体首先丢失一个id。

    请注意,您希望在自定义构造函数中分配id, Objectify用于在加载时构建实体的no-args构造函数。分配ID很便宜,但仍然是对GAE服务层的调用,并且您不希望在每次加载时都这样做。