简而言之
我似乎已经多次出现了保存对象的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。因此,所有客户端代码都可以使用此方法获取新的临时对象,或者用于获取现有持久化实例的明显客观化负载。简单。完成。可爱。
答案 0 :(得分:1)
我推荐两件事:
ObjectifyFactory.allocateId()
构建对象时手动分配ID。不要使用&#34; save with null autogenerates&#34;特征。正如您所注意到的,它是一个PITA来处理具有空ID的实体对象,因此不允许它们存在。ofy().defer().save().entity(blah);
您可以通过这种方式保存几乎任何数量的内容,并且只有在提交(或关闭客观化会话)时才会保存一次。延迟多次保存在同一实体上只会产生一次保存。这种留下ids的模式为null并在保存时填充它是JPA日的延续。它与JPA的合作也不是很好;有很多令人沮丧的边缘案例处理实体缺少id(特别是当你想放入地图或集合时)。最好的解决方案是简单地保证没有实体首先丢失一个id。
请注意,您希望在自定义构造函数中分配id,不 Objectify用于在加载时构建实体的no-args构造函数。分配ID很便宜,但仍然是对GAE服务层的调用,并且您不希望在每次加载时都这样做。