【发布时间】:2015-04-28 07:56:07
【问题描述】:
存储和查询 Objectify 实体的正确方法是什么,该实体涉及标有 Objectify 的 @Parent 注释的字段?请提供使用ancestor() 查询的示例。
【问题讨论】:
标签: java google-app-engine objectify
存储和查询 Objectify 实体的正确方法是什么,该实体涉及标有 Objectify 的 @Parent 注释的字段?请提供使用ancestor() 查询的示例。
【问题讨论】:
标签: java google-app-engine objectify
有几个要求:
索引 - 确保查询的字段已编入索引
祖先 - 确保使用ancestor(parent)
提交 - 确保已提交保存
附件 - 确保将子项附加到父项并保存
验证 id 是否匹配,而不是 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 在 cmets 中提到这一点。
这是我正在编写的一些代码的草图,我让它在单元测试中工作。
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();
}
}
我的物品
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);
}
}
我的类别
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
@Entity
public class MyCategory {
@Id public Long id;
}
datastore-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 而失败)。
【讨论】:
ancestor(),整个查询是强一致的?