我有一个引用用户对象的帐户对象。
@Cache
@Entity
public final class Account {
@Id Long id;
@Index private Ref<User> user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user.get();
}
public void setUser(User user) {
this.user = Ref.create(user);
}
}
我按照此处的建议隐藏了参考:http://code.google.com/p/objectify-appengine/wiki/Entities - 请注意参考不是否有@Load注释。
当我从Android客户端调用我的Google Cloud Endpoint时,看起来Objectify会向嵌入式用户提供帐户对象,即使未指定@Load也是如此。
@ApiMethod(name = "account.get")
public Account getAccount(
@Named("id") final Long id
) {
return ofy().load().type(Account.class).id(id).now();
}
当我使用Apis Explorer直接查询帐户时,我同时获得了嵌入用户的帐户:
200 OK
{
"id": "5079604133888000",
"user": { "id": "5723348596162560",
"version": "1402003195251",
"firstName": "Karl" },
"kind": "api#accountItem",
"etag": "\"30khohwUBSGWr00rYOZuF9f4BTE/Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\""}
这提出了三个问题:
答案 0 :(得分:13)
在您的示例代码中,您没有指定@Load
,这意味着加载帐户将无法获取User
。但是,您的@ApiMethod
正在将帐户序列化回客户端,因此已访问user
属性,因此会发出单独的提取以加载用户对象。这就是您在调用方法时获取用户信息的原因。
不指定@Load
并不意味着您无法获得User
。这意味着除非您稍后特别要求,否则您不会检索User
。
Ref的工作原理如下:
@Load
,那么我最初会获取数据,并为你做好准备。所以这在你的代码中工作得很好......但是你的@ApiMethod
正在将你的Account
对象序列化回客户端。序列化过程将遍历Account
对象中的每个属性,包括user
属性。此时,正在访问Ref<User>
,因此数据将从数据存储区中获取,然后返回给客户端。
这使得您的代码效率非常低,因为Account
对象在没有User
信息的情况下加载,但是您以后总是访问User
信息(在序列化期间),发出一个单独获取。从数据存储区域批处理gets
比发布单独的gets
更有效。
在您的情况下,您可以执行以下两种操作之一:
@Load
添加到用户属性,以便有效获取Account
对象。@ApiMethod
返回不具有Account
属性的其他user
对象(因此,如果您不需要,则可以避免抓取用户)。上面的选项2非常有用,因为您可以从客户端看到的内容中抽象出内部数据存储区结构。你会发现自己经常使用这种模式。