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 将对此做的是
- 查询实际实体
- 如果为您的实体的属性之一定义了@Load,则该属性的值将放在列表中
- Objectify 做了一个
load().keys(<ListFrom2>)
- 您现在可以使用
Ref#get()
-方法,它后面的实体已经加载
因此您可以使用@Load 批注,但即使您不需要它们,它也会始终加载 Refs。我通常自己创建一个加载数据的方法。基本上我实现了 1-4 中的所有步骤,除了没有 @Load 注释并且我的方法创建了键列表来加载自身。这里唯一的问题是将结果 Entities 与 Ref 匹配(实际上这不是一个大问题,因为以集合作为参数的键查询的结果是一个以实体键作为键的 Map)
其次,如果您希望 to/must 保持您的实体不变。
尝试减少对数据存储的调用量并在内存中进行一些排序:
ofy.load().ancestor(Key.create(Problem.class, "ProblemName"))
将为您提供 Problem
和所有相关的 Tuple
和 Attribute
。如果您还需要 CategorizedData
,请将 CategorizedData
设为 Problem
的子项,并使用不带 @Parent 的简单 Ref<Attribute>
引用 Attribute
。话又说回来:如果这是我的代码,我会让 CategroizedData
成为 Attribute
的嵌入式 List
。
在处理祖先查询的结果时,您可以自己进行各种过滤和排序。这将比执行数百个查询快得多。
综上所述,我认为您的问题源于在设计实体时没有考虑数据的实际使用。尽可能去规范化,将冗余数据视为一种选择,而不是不可行的。
这道题的基本思路如下。我执行一些查询
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 将对此做的是
- 查询实际实体
- 如果为您的实体的属性之一定义了@Load,则该属性的值将放在列表中
- Objectify 做了一个
load().keys(<ListFrom2>)
- 您现在可以使用
Ref#get()
-方法,它后面的实体已经加载
因此您可以使用@Load 批注,但即使您不需要它们,它也会始终加载 Refs。我通常自己创建一个加载数据的方法。基本上我实现了 1-4 中的所有步骤,除了没有 @Load 注释并且我的方法创建了键列表来加载自身。这里唯一的问题是将结果 Entities 与 Ref 匹配(实际上这不是一个大问题,因为以集合作为参数的键查询的结果是一个以实体键作为键的 Map)
其次,如果您希望 to/must 保持您的实体不变。 尝试减少对数据存储的调用量并在内存中进行一些排序:
ofy.load().ancestor(Key.create(Problem.class, "ProblemName"))
将为您提供 Problem
和所有相关的 Tuple
和 Attribute
。如果您还需要 CategorizedData
,请将 CategorizedData
设为 Problem
的子项,并使用不带 @Parent 的简单 Ref<Attribute>
引用 Attribute
。话又说回来:如果这是我的代码,我会让 CategroizedData
成为 Attribute
的嵌入式 List
。
在处理祖先查询的结果时,您可以自己进行各种过滤和排序。这将比执行数百个查询快得多。
综上所述,我认为您的问题源于在设计实体时没有考虑数据的实际使用。尽可能去规范化,将冗余数据视为一种选择,而不是不可行的。