存储和查询涉及标有Objectify @Parent
注释的字段的Objectify实体的正确方法是什么?请使用ancestor()
查询提供示例。
答案 0 :(得分:4)
有几个要求:
索引 - 确保查询的字段已编入索引
祖先 - 请务必使用ancestor(parent)
提交 - 确保已提交保存
附件 - 确保将孩子附加到父母并保存
验证ids是否匹配,而不是Java对象实例 - 当您将其读回时,它将是一个不同的Java对象。但标有Objectify的@Id的字段应该是相同的
使用.now()保存并使用.now()回读 - 请参阅Why .now()? (Objectify)和Objectify error "You cannot create a Key for an object with a null @Id" in JUnit
请勿尝试使用标记为@Parent的字段作为您要过滤的字段;重复该字段
datastore-indexes.xml - 如果您要查询实体并对多个字段进行过滤,则Objectify的@Index
注释是不够的。您还必须在[datastore-indexes.xml](https://cloud.google.com/appengine/docs/java/config/indexconfig)
中输入一个条目。感谢Patrice在评论中提到这一点。
这是我正在编写的一些代码的草图,我将其用于单元测试。
<强> RepositoryTest 强>
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import com.googlecode.objectify.ObjectifyService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class RepositoryTest {
// Tests under worst case of replication https://stackoverflow.com/questions/27727338/which-is-better-setdefaulthighrepjobpolicyunappliedjobpercentage100-vs-custo
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
private Closeable closeable;
private Repository repository;
@Before
public void setup() {
helper.setUp();
repository = new Repository();
ObjectifyService.register(MyCategory.class);
ObjectifyService.register(MyItem.class);
closeable = ObjectifyService.begin(); // https://stackoverflow.com/questions/27726961/how-to-resolve-you-have-not-started-an-objectify-context-in-junit
}
@After
public void tearDown() {
closeable.close();
helper.tearDown();
}
@Test
public void testLookupMyItemShouldSucceed() {
MyCategory myCategory = repository.createMyCategory();
int zero = 0;
int one = 1;
int two = 2;
addMyItem(myCategory, zero, "a");
MyItem expectedMyItem = addMyItem(myCategory, one, "b");
addMyItem(myCategory, two, "c");
MyItem actualMyItem = repository.lookupMyItem(myCategory, one);
assertThat(actualMyItem, Matchers.notNullValue());
assertThat(actualMyItem.id, equalTo(expectedMyItem.id));
}
private MyItem addMyItem(MyCategory myCategory, long index, String label) {
MyItem myItem = repository.createMyItem();
myItem.setParent(myCategory);
myItem.setGroup(myCategory);
myItem.index = index;
myItem.label = label;
repository.updateMyItem(myItem);
}
}
<强>存储库强>
import static com.googlecode.objectify.ObjectifyService.begin;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.util.Closeable;
public class Repository {
public Topic createMyCategory() {
Topic entity = topicProvider.get();
updateTopic(entity);
return entity;
}
public MyItem lookupMyItem(MyCategory myCategory, long i) {
return ofy().load().type(MyItem.class).ancestor(myCategory).filter(MyItem.MyCategoryField, myCategory).filter(MyItem.IndexField, i).first().now();
}
}
<强> MyItem 强>
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.Parent;
@Entity
public class MyItem {
@Id public Long id;
@Parent private Ref<MyCategory> parent;
@Index private Ref<MyCategory> myCategory; public static final String MyCategoryField = "myCategory";
@Index public Long index; public static final String IndexField = "index";
public String label;
public long weight;
public MyCategory getGroup() {
return group.get();
}
public void setGroup(MyCategory group) {
this.group = Ref.create(group);
}
public MyCategory getParent() {
return parent.get();
}
public void setParent(MyCategory group) {
this.parent = Ref.create(group);
}
}
<强> MyCategory 强>
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
@Entity
public class MyCategory {
@Id public Long id;
}
<强>数据存储-indexes.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
<datastore-index kind="MyItem" ancestor="true">
<property name="myCategory" direction="asc" />
<property name="index" direction="asc" />
</datastore-index>
</datastore-indexes>
上面的代码中可能存在语法错误或拼写错误,因为为了清晰起见,我从原始代码修改了此错误。单元测试确实通过并且它一致地传递(即,由于eventual consistency,它有时不会失败。)