Objectify在Ref<>后加载对象。即使没有指定@Load也是如此 [英] Objectify loads object behind Ref<?> even when @Load is not specified

查看:100
本文介绍了Objectify在Ref<>后加载对象。即使没有指定@Load也是如此的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  @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\}

这提出了三个问题:


  1. Appengine是否始终以本机方式返回嵌入的Refs,Objectify是否总是传递它已知的对象? / li>
  2. @Load是什么以及是否有办法控制这种行为?加载组?

  3. 我错过了什么吗?为什么不@Load服从?


解决方案

在您的示例代码中, @Load 这意味着加载账户不会获取 User 。但是,您的 @ApiMethod 会将该帐户序列化回客户端,因此用户属性已被访问,因此发出单独的提取来加载用户对象。这就是为什么你在调用方法时获取用户的信息。



不指定 @Load 不会意味着你不会得到 User 回来。这意味着你将不会检索 User ,除非你稍后特意要求它。



参考资料是这样的:


  • 我是一个参考,所以通过默认情况下,我不会获取数据。

  • 如果您要求我,我会先加载数据,然后回答您。 ,如果你告诉我 @Load 我自己,那么我将首先获取数据并准备好给你。



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



由于 Account 对象在没有 User 的情况下被加载,信息,但随后您总是在稍后(在序列化期间)访问用户信息,发出单独的提取。从数据存储批处理获得比单独发布获得更高效。



在您的情况下,您可以执行以下任一操作:


  1. 添加 @Load code>给用户属性,所以 Account 对象被有效地取得。

  2. 让你的 @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:

    1. Does Appengine always return embedded Refs natively and does Objectify always pass on objects which it already knows?
    2. What exactly is @Load for and is there a way to control this behavior? Load Groups?
    3. 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 the User. However, your @ApiMethod is serializing the account back to the client, so the user 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 a User back. It means that you are not going to retrieve a User 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 your Account object back to the client. The serialization process is going through every property in your Account object, including the user property. At this point, the Ref<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 the User information, but then you always access the User info later (during serialization), issuing a separate fetch. Batching gets from the Datastore is way more efficient than issuing separate gets.

    In your case, you can do either of two things:

    1. Add @Load to the user property, so the Account object is fetched efficiently.
    2. Make your @ApiMethod return a different Account object without the user 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&lt;&gt;后加载对象。即使没有指定@Load也是如此的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆