即使没有指定@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\""} 

这提出了三个问题:

  1. Appengine是否总是本机返回嵌入的Refs并且Objectify是否总是传递它已经知道的对象?
  2. @Load究竟是什么,有没有办法控制这种行为? 加载组?
  3. 我错过了什么吗? @Load为什么不遵守?

在您的示例代码中,您没有指定@Load ,这意味着加载帐户将不会获取User 。 但是,您的@ApiMethod将帐户序列化回客户端,因此访问了user属性,因此会发出单独的提取来加载用户对象。 这就是您在调用方法时获取用户信息的原因。

不指定@Load并不意味着您不会让User回来。 这意味着除非您稍后特别要求,否则您不会检索User

Ref的工作原理如下:

  • 我是一个参考,所以默认情况下我不会获取数据。
  • 如果您要求我,那么我将首先加载数据,然后回答您。
  • 哦,如果你自己告诉我@Load ,那么我最初会获取数据并为你做好准备。

所以这在你的代码中工作正常……但是你的@ApiMethod正在将你的Account对象序列化回客户端。 序列化过程将遍历Account对象中的每个属性,包括user属性。 此时,正在访问Ref ,因此数据将从数据存储区中获取,然后返回到客户端。

这使得您的代码效率非常低,因为在没有User信息的情况下加载了Account对象,但随后您总是访问User信息(在序列化期间),发出单独的提取。 从数据存储中gets批处理比发出单独的gets更有效。

在您的情况下,您可以执行以下两种操作之一:

  1. @Load添加到用户属性,以便有效地获取Account对象。
  2. 使@ApiMethod返回不同的Account对象而不使用user属性(因此,如果您不需要,则避免提取用户)。

上面的选项2非常有用,因为您可以从客户端看到的内容中抽象出内部数据存储区结构。 你会发现自己经常使用这种模式。