2015-04-24 64 views
0

我使用Objectify在Google App Engine的数据存储上存储数据。我一直试图实现两个类之间的一对多关系,但是通过存储参数化键的列表。下面的方法在某些时候完美工作,但是其他时候会返回一个空数组 - 有人知道为什么这可能是?Objectify并不总是返回结果

它要么返回CourseYears的正确列表,或

{ 
"items": [ 
] 
} 

这里是方法:

@ApiMethod(name = "getCourseYears") @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
public ArrayList<CourseYear> getCourseYears(@Named("name") String name){ 

    Course course = ofy().load().type(Course.class).filter("name", name).first().now(); 
    System.out.println(course.getName()); 

    ArrayList<CourseYear> courseYears = new ArrayList<CourseYear>(); 
    for(Key<CourseYear> courseYearKey: course.getCourseYears()){ 
     courseYears.add(ofy().load().type(CourseYear.class).id(courseYearKey.getId()).now()); 
    } 

    return courseYears; 
} 

存储许多CourseYear键

@Entity 
public class Course { 
@Id 
@Index 
private Long courseId; 

private String code; 

@Index 
private String name; 

@ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
public List<Key<CourseYear>> getCourseYears() { 
    return courseYears; 
} 

@ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
public void setCourseYears(List<Key<CourseYear>> courseYears) { 
    this.courseYears = courseYears; 
} 

@ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
    public void addCourseYear(Key<CourseYear> courseYearRef){ 
    courseYears.add(courseYearRef); 
} 
@Load 
@ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
List<Key<CourseYear>> courseYears = new ArrayList<Key<CourseYear>>(); 

... 

} 

我的课程班我正在使用API​​浏览器在调试服务器上调试它。我发现它通常会在开始时工作几次,但如果我离开并返回到API并尝试再次运行它,那么在此之后它不会再开始工作。

有没有人有任何想法可能会出错?

非常感谢。

回答

1

您可能想要减少发送到数据存储的查询量。尝试是这样的:

Course course = ofy().load().type(Course.class).filter("name", name).first().now(); 

ArrayList<CourseYear> courseYears = new ArrayList<CourseYear>(); 
List<Long> courseIds = new List<>(); 
for(Key<CourseYear> courseYearKey: course.getCourseYears()){ 
    courseIds.add(courseYearKey.getId()); 
} 
Map<Long, Course> courses = ofy().load().type(CourseYear.class).ids(courseIds).list(); 
// add all courses from map to you courseYears list 

我也强烈建议改变你的数据结构/实体:

在你CourseYears添加属性Ref<Course> courseRef与父进程,并使其索引(@Index)。然后通过查询

ofy().load().type(CourseYear.class).filter("courseRef", yourCourseRef).list(); 

这样你只需要一个查询。

+0

谢谢你的建议。我意识到我可能不会正确维护键/引用列表 - 是否足以维护列表的以下代码? Ref key = Ref.create(courseYear); course.addCourseYear(key); – Eden

+0

你显然有关系数据库的背景。有了云数据仓库,你有时不得不思考倒退。不要尝试将规范化规则应用于数据存储,考虑要查询的内容以及最有效的查询是什么样的。然后相应地设计你的实体。您不应该维护一个键列表,该列表将在数据存储中序列化,并且您无法按列表或其内容过滤查询。将Ref(外键)添加到您的decendant(n)实体,并通过Ref进行查询。 – konqi

+0

我想我已经有效了!我已经尝试了你在过去描述的内容,但它确实按照你描述的方式点击了。非常感谢你,我一直在努力工作,并且强调这一点,现在已经全部排序了! – Eden

0

两个最可能的候选人是:高复制数据存储的

  1. 最终一致性行为。查询(也就是你的filter()操作)总是稍微落后一点,因为索引通过GAE异步传播。请参阅GAE文档。
  2. 您尚未安装ObjectifyFilter。阅读安装指南。如果你没有安装Objectify,最近的版本会抛出一个错误,所以如果你使用的是最新版本,那就不是这样。