GAE Objectify如何将查询结果用于另一个查询

GAE Objectify how to use result of query to another query

这道题的基本思路如下。我执行一些查询

      List<Class2> class2entities = ObjectifyService.ofy()
          .load()
          .type(Class2.class) 
          .filter(?,?)    
          .list();

我可以用什么方式执行另一个基于 class2entities 的查询?

实际上我正在开发基于 Objectify 的 GAE 应用程序。我使用以下实体

问题:

 @Entity
public class Problem {
  @Id public String problemname;

  public Problem (String name) {
      problemname = name;
  }

  public Problem () {
      problemname = "nullProblem";
  }
}

元组:

    @Entity
public class Tuple {
  @Parent Ref<Problem> theProblem;
  @Index public String tuple_id;
  @Id public Long id;

public Tuple()
{
    String s="empty operator";
}

public Tuple(String sid, Problem problem)
{
    tuple_id = sid;
    try {
         theProblem = Ref.create(problem);
    }
    catch (java.lang.NullPointerException e)
    {
        System.out.println(e.toString() + " tuple in datastore was not created because of Problem is empty" );
    }
}
}

属性:

@Entity
public class Attribute {
  @Parent com.googlecode.objectify.Ref<Problem> theProblem;
  @Id public Long id;

  public String attributeName;
  @Index public String attributeFieldName;
  @Index public Date date;

  /**
   * Simple constructor just sets the date
   **/
  public Attribute() {
    date = new Date();
  }

  /**
   * A connivence constructor
   **/
  public Attribute(Problem problem, String attributeName) {
    this();
    if( problem != null ) {
      theProblem = Ref.create(problem);  // Creating the Ancestor key
    } else {
      theProblem = Ref.create(new Problem("nullProblem"));
    }
    this.attributeName = attributeName;
  }

  /**
   * Takes all important fields
   **/
  public Attribute(Problem problem, String attributeName, String var_attributeFieldName) {
    this(problem, attributeName);
    attributeFieldName = var_attributeFieldName;
  }

}

分类数据:

@Entity
public class CategorizedData {
  @Load public Ref<Attribute> theAttribute;
  @Id Long id;
  @Parent public Key<Tuple> theTuple;
  public String attributeValue;

  @Index public Date date;


  /**
   * getter and setter for theAttribute
   **/

    public Attribute getAttribute() { return theAttribute.get(); }
    public void setAttribute(Attribute attribute) { theAttribute = Ref.create(attribute); }

  /**
   * Simple constructor just sets the date
   **/
  public CategorizedData() {
    date = new Date();
  }

  /**
   * A connivence constructor
   **/
  public CategorizedData(String tupleId, String attribute_field_name, String var_attributeValue) {
    this();
    Attribute attribute = ofy().load().type(Attribute.class).filter("attributeFieldName", attribute_field_name).first().now();
    Tuple tuple = ofy().load().type(Tuple.class).filter("tuple_id",tupleId).first().now();

    if( tupleId != null ) {
      theTuple = Key.create(Tuple.class, tuple.id);          // Creating the Ancestor key
    } else {
      theTuple = Key.create(Tuple.class, (new Tuple()).id);
    }
    if( attribute != null ) {
      theAttribute = Ref.create(attribute);  // Creating the Ancestor ref
    } else {
      theAttribute = Ref.create(new Attribute());
    }
    this.attributeValue = var_attributeValue;
  }

}

现在我想获取给定问题的所有元组实体,并获取具有给定属性字段名称的属性字段的所有 CategorizedData 实体。

我需要做类似

的事情
Key<Problem> theProblem = Key.create(Problem.class, problemName);
    // Run an ancestor query 
      List<Tuple> tuples = ObjectifyService.ofy()
          .load()
          .type(Tuple.class) 
          .ancestor(theProblem)    
          .list();

然后我需要在此列表元组中获取 CategorizedData 的实体。 我应该怎么办?是否可以将先前查询的结果用于 Objectify 查询而不是所有数据存储?请帮助我...

您的问题有几个解决方案。但首先我想说您的实体可能针对数据存储设计不当。使用数据存储时,您应该通过分析要查询的内容来创建实体。

一个例子:

您有一个 Problem 实体和一个 Tuple 实体,但您的 Problem 实体只有一个属性 (problemname)。数据存储方法是将这种关系非规范化,并将 problemname 属性放入您的 Tuple 实体中(或将 Tuple 属性放入 Problem 中)。这样,您可以从查询 Tuple 实体开始,并且您已经拥有正式两个实体的数据。是的,这意味着您的数据存储中将有冗余数据,但从数据存储的角度来看这很好。

现在来解决你的实际问题

Objectify 允许您将 @Load 注释设置为 Ref<Something>。 Objectify 将对此做的是

  1. 查询实际实体
  2. 如果为您的实体的属性之一定义了@Load,则该属性的值将放在列表中
  3. Objectify 做了一个 load().keys(<ListFrom2>)
  4. 您现在可以使用 Ref#get()-方法,它后面的实体已经加载

因此您可以使用@Load 批注,但即使您不需要它们,它也会始终加载 Refs。我通常自己创建一个加载数据的方法。基本上我实现了 1-4 中的所有步骤,除了没有 @Load 注释并且我的方法创建了键列表来加载自身。这里唯一的问题是将结果 Entities 与 Ref 匹配(实际上这不是一个大问题,因为以集合作为参数的键查询的结果是一个以实体键作为键的 Map)

其次,如果您希望 to/must 保持您的实体不变。 尝试减少对数据存储的调用量并在内存中进行一些排序:

ofy.load().ancestor(Key.create(Problem.class, "ProblemName"))

将为您提供 Problem 和所有相关的 TupleAttribute。如果您还需要 CategorizedData,请将 CategorizedData 设为 Problem 的子项,并使用不带 @Parent 的简单 Ref<Attribute> 引用 Attribute。话又说回来:如果这是我的代码,我会让 CategroizedData 成为 Attribute 的嵌入式 List。 在处理祖先查询的结果时,您可以自己进行各种过滤和排序。这将比执行数百个查询快得多。

综上所述,我认为您的问题源于在设计实体时没有考虑数据的实际使用。尽可能去规范化,将冗余数据视为一种选择,而不是不可行的。