即使没有指定@Load,Objectify也会在Ref 后面加载对象
我有一个引用用户对象的帐户对象。
@Cache @Entity public final class Account { @Id Long id; @Index private Ref 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\""}
这提出了三个问题:
- Appengine是否总是本机返回嵌入的Refs并且Objectify是否总是传递它已经知道的对象?
- @Load究竟是什么,有没有办法控制这种行为? 加载组?
- 我错过了什么吗? @Load为什么不遵守?
在您的示例代码中,您没有指定@Load
,这意味着加载帐户将不会获取User
。 但是,您的@ApiMethod
将帐户序列化回客户端,因此访问了user
属性,因此会发出单独的提取来加载用户对象。 这就是您在调用方法时获取用户信息的原因。
不指定@Load
并不意味着您不会让User
回来。 这意味着除非您稍后特别要求,否则您不会检索User
。
Ref的工作原理如下:
- 我是一个参考,所以默认情况下我不会获取数据。
- 如果您要求我,那么我将首先加载数据,然后回答您。
- 哦,如果你自己告诉我
@Load
,那么我最初会获取数据并为你做好准备。
所以这在你的代码中工作正常……但是你的@ApiMethod
正在将你的Account
对象序列化回客户端。 序列化过程将遍历Account
对象中的每个属性,包括user
属性。 此时,正在访问Ref
,因此数据将从数据存储区中获取,然后返回到客户端。
这使得您的代码效率非常低,因为在没有User
信息的情况下加载了Account
对象,但随后您总是访问User
信息(在序列化期间),发出单独的提取。 从数据存储中gets
批处理比发出单独的gets
更有效。
在您的情况下,您可以执行以下两种操作之一:
- 将
@Load
添加到用户属性,以便有效地获取Account
对象。 - 使
@ApiMethod
返回不同的Account
对象而不使用user
属性(因此,如果您不需要,则避免提取用户)。
上面的选项2非常有用,因为您可以从客户端看到的内容中抽象出内部数据存储区结构。 你会发现自己经常使用这种模式。