Java Objectify在Ref<;后面加载对象&燃气轮机;即使未指定@Load
我有一个引用用户对象的account对象Java Objectify在Ref<;后面加载对象&燃气轮机;即使未指定@Load,java,google-app-engine,google-cloud-endpoints,objectify,Java,Google App Engine,Google Cloud Endpoints,Objectify,我有一个引用用户对象的account对象 @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 U
@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);
}
}
当我直接使用API资源管理器查询帐户时,我也会同时获得这两个帐户,即嵌入用户的帐户:
200 OK
{
"id": "5079604133888000",
"user": { "id": "5723348596162560",
"version": "1402003195251",
"firstName": "Karl" },
"kind": "api#accountItem",
"etag": "\"30khohwUBSGWr00rYOZuF9f4BTE/Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\""}
这提出了三个问题:
在示例代码中,您没有指定
@Load
,这意味着加载帐户不会获取用户
。但是,您的@ApiMethod
正在将帐户序列化回客户端,因此访问了user
属性,因此会发出单独的获取来加载用户对象。这就是为什么在调用该方法时会获得用户的信息
不指定@Load
并不意味着您将无法获得用户
。这意味着您不会检索用户
,除非您以后特别要求它
Ref的工作原理如下:
- 我是一个引用,所以默认情况下我不会获取数据
- 如果你问我,我会先加载数据,然后回答你
- 哦,如果你让我自己加载,那么我会先提取数据并准备好给你
@ApiMethod
正在将您的帐户
对象序列化回客户端。序列化过程将遍历帐户
对象中的每个属性,包括用户
属性。此时,正在访问Ref
,因此数据将从数据存储中获取,然后返回到客户端
这使得您的代码非常低效,因为加载帐户
对象时没有用户
信息,但之后(序列化期间)您总是访问用户
信息,并发出单独的获取。从数据存储中批处理get
比单独发出get
更有效
在您的情况下,您可以执行以下两种操作之一:
@Load
添加到用户属性,以便有效地获取帐户
对象@ApiMethod
返回一个不同的帐户
对象,而不使用用户
属性(这样可以避免在不需要时获取用户)上面的选项2非常有用,因为您可以从客户机看到的内容中抽象出内部数据存储结构。你会发现自己经常使用这种模式。谢谢@svpino给出的非常详细的答案,我相信这对所有使用objectify with REST的人来说都非常重要。我不清楚,即使我没有从代码中显式地访问Ref,序列化程序也会这样做。如果我在发送到客户端之前显式地将用户对象设置为null会怎么样?
200 OK
{
"id": "5079604133888000",
"user": { "id": "5723348596162560",
"version": "1402003195251",
"firstName": "Karl" },
"kind": "api#accountItem",
"etag": "\"30khohwUBSGWr00rYOZuF9f4BTE/Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\""}