关于在数据存储区中使用嵌入式实体,我有几个问题。
考虑以下简单的测试用例:
Entity entity = new Entity("Person");
entity.setProperty("name", "Alice");
EmbeddedEntity address = new EmbeddedEntity();
address.setProperty("streetAddress", "100 Main Street");
address.setProperty("addressLocality", "Springfield");
address.setProperty("addressRegion", "VA");
entity.setProperty("address", address);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(entity);
Query query = new Query("Person");
FilterPredicate regionFilter =
new FilterPredicate("address.addressRegion", FilterOperator.EQUAL, "VA");
query.setFilter(regionFilter);
List<Entity> results = datastore.prepare(query)
.asList(FetchOptions.Builder.withDefaults());
assertEquals(1, results.size());
此测试失败;结果集为空。
以下是我的问题:
Datastore documentation包含以下声明:
&#34;当嵌入式实体包含在索引中时,您可以查询子属性。&#34;
我遵循关于Java Local Unit Testing的文章中的说明,但文章中没有解释如何在JUnit测试中定义索引的内容。
答案 0 :(得分:1)
由于最终的一致性,这项测试很不稳定。
由于您没有进行祖先查询,因此查询最终使用一致的索引(SELECT * FROM Person WHERE address.addressRegion = "VA"
)。插入和查询不能保证匹配相同的副本,address.addressRegion
也不能保证更新。
默认情况下,嵌入式实体应编入索引,以免出现问题。
最终的一致性通常以毫秒为单位进行解决,但由于您正在立即编写和查询,因此您更有机会点击它。
您可以采用两种策略来降低测试的薄脆度。
在put和查询之间添加1或2秒的睡眠将减少测试的瑕疵,但不能消除它 - 可能是合理的第一步。我一眼就看出它没有运行你的代码。
Cloud Datastore同步将实体写入多数副本,但是在此步骤之后异步应用索引 - 这会导致某些查询的最终一致性。
您可以通过执行相关实体的读取来强制应用索引。读取实体时,将检查实体组的写日志,以查看是否存在要应用的未完成写入 - 如果在读取之前强制应用它们。您可以在单元测试中使用此机制来减少最终的一致性问题。
此外,要验证实体是否按预期编写,您可以跳转到云控制台并从上面执行GQL语句。