Objectify在Ref<>后加载对象。即使没有指定@Load也是如此 [英] Objectify loads object behind Ref<?> even when @Load is not specified
问题描述
@Cache
@实体
我有一个引用用户对象的账户对象。 public final class Account {
@Id Long id;
@Index private Ref< User>用户;
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
$ b $ public User getUser(){
return user.get();
}
public void setUser(User user){
this.user = Ref.create(user);
}
}
此处: http://code.google.com/p/objectify-appengine/wiki /实体 - 请注意Ref does not 具有@Load注释。
当我从一个Google Cloud Endpoint Android客户端,即使没有指定@Load,它看起来像Objectify为嵌入式用户提供帐户对象。
@ApiMethod (name =account.get)
public Account getAccount(
@Named(id)final Long id
){
return ofy()。load()。类型(Account.class).ID(ID)。现在();
}
当我使用Apis Explorer直接查询帐户时,嵌入用户:
200 OK
{
id:5079604133888000,
user:{id:5723348596162560,
version:1402003195251,
firstName:Karl},
kind:api #accountItem,
etag:\30khohwUBSGWr00rYOZuF9f4BTE / Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\}
这提出了三个问题:
- Appengine是否始终以本机方式返回嵌入的Refs,Objectify是否总是传递它已知的对象? / li>
- @Load是什么以及是否有办法控制这种行为?加载组?
- 我错过了什么吗?为什么不@Load服从?
在您的示例代码中, @Load
这意味着加载账户不会获取 User
。但是,您的 @ApiMethod
会将该帐户序列化回客户端,因此
不指定 @Load
不会意味着你不会得到 User
回来。这意味着你将不会检索 User
,除非你稍后特意要求它。
参考资料是这样的:
@Load
我自己,那么我将首先获取数据并准备好给你。
所以这在你的代码中工作正常......但是你的 @ApiMethod
正在序列化你的 Account
对象返回给客户端。序列化过程遍历 Account
对象中的每个属性,包括 user
属性。此时,正在访问 Ref< User>
,因此数据将从数据存储中获取,然后返回给客户端。
由于 Account
对象在没有 User
的情况下被加载,信息,但随后您总是在稍后(在序列化期间)访问用户
信息,发出单独的提取。从数据存储批处理获得
比单独发布获得
更高效。
在您的情况下,您可以执行以下任一操作:
- 添加
@Load code>给用户属性,所以
Account
对象被有效地取得。 - 让你的
@ApiMethod
不带用户
属性返回一个不同的Account
对象(从而避免提取用户如果您不需要它)。
上面的选项2非常有用,因为您可以从客户端的内容中抽象出内部数据存储区结构看到。你会发现自己经常使用这个模式。
I have an account object which references a user object.
@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); } }
I have hidden the Ref as recommended here: http://code.google.com/p/objectify-appengine/wiki/Entities - please note the Ref does not have the @Load annotation.
When I call my Google Cloud Endpoint from an Android client, it looks like Objectify delivers the account object with the embedded user, even though @Load is not specified.
@ApiMethod(name = "account.get") public Account getAccount( @Named("id") final Long id ) { return ofy().load().type(Account.class).id(id).now(); }
When I query the account directly using Apis Explorer, I also get both, account with the user embedded:
200 OK { "id": "5079604133888000", "user": { "id": "5723348596162560", "version": "1402003195251", "firstName": "Karl" }, "kind": "api#accountItem", "etag": "\"30khohwUBSGWr00rYOZuF9f4BTE/Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\""}
This raises three questions:
- Does Appengine always return embedded Refs natively and does Objectify always pass on objects which it already knows?
- What exactly is @Load for and is there a way to control this behavior? Load Groups?
- Have I missed something? Why isn't @Load obeyed?
解决方案In your example code, you are not specifying
@Load
which means that loading the account will not fetch theUser
. However, your@ApiMethod
is serializing the account back to the client, so theuser
property is been accessed, thus a separate fetch is issued to load the user object. That's why you are getting the information of the user when calling the method.Not specifying
@Load
doesn't mean that you won't get aUser
back. It means that you are not going to retrieve aUser
unless you specifically ask for it later.Ref works like this:
- I'm a reference, so by default I won't fetch the data.
- If you ask for me, then I will first load the data, then answer you.
- Oh, if you tell me to
@Load
myself, then I will fetch the data initially and have it ready for you.
So this is working fine in your code... but then your
@ApiMethod
is serializing yourAccount
object back to the client. The serialization process is going through every property in yourAccount
object, including theuser
property. At this point, theRef<User>
is being accessed, so the data will get fetched from the Datastore and then returned to the client.This is making your code very inefficient, since the
Account
objects are loaded without theUser
information, but then you always access theUser
info later (during serialization), issuing a separate fetch. Batchinggets
from the Datastore is way more efficient than issuing separategets
.In your case, you can do either of two things:
- Add
@Load
to the user property, so theAccount
object is fetched efficiently. - Make your
@ApiMethod
return a differentAccount
object without theuser
property (thus avoiding fetching the user if you don't need it).
Option 2 above is quite useful since you can abstract your internal Datastore structure from what the client sees. You'll find yourself using this patter quite often.
这篇关于Objectify在Ref<>后加载对象。即使没有指定@Load也是如此的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!