有两种实体:User 和 Trip。用户是 Trip 的父级,而 Trip 是 User 的子级。
出于隐私考虑,我只发布旅行 ID/名称。因为它看起来像旅行密钥包含编码的用户 ID/名称。
如果父键未知,如何通过 ID/名称获取实体?
有两种实体:User 和 Trip。用户是 Trip 的父级,而 Trip 是 User 的子级。
出于隐私考虑,我只发布旅行 ID/名称。因为它看起来像旅行密钥包含编码的用户 ID/名称。
如果父键未知,如何通过 ID/名称获取实体?
你不能。父键是实体键的一部分,您需要一个完整的键来获取实体。
除非您指定祖先键,否则使用键过滤器查询也不会找到具有父级的实体。
如果您在“根”实体下创建所有“用户”实体并向“旅行”实体添加“uuid”属性,则可以查找具有指定 UUID 的单个“旅行”。
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
@peter-knego 在最初的问题中:用户是 Trip 的父母。要通过 id 获取实体,您需要使用父项重建密钥以获取完整密钥。但是您可以避免这种情况,只需为 Trip 的完整密钥分配 id。您可以使用分配的 id 构造完整的密钥。这是我的逻辑。
你可以这样做:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException{
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
}
我制定了 3 个可以解决此问题的替代方案,恕我直言,这是一个非常重要的替代方案。
---- 第一种选择 ----
如果您的行程 ID 是根据其他属性计算的,则有一种方法。而不是Trip
通过id
它从其他计算属性中获取它。让我们想象一下,您的 Trip 的 id 是由某个规范名称(您从其完整标题推断出的 URN)计算得出的,例如,如果 Trip 的全名是
珠穆朗玛峰之旅
您的规范名称可能是voyage-to-the-everest
,这是您用作密钥名称的字符串。因此,不要使用 use 获取元素datastore.get
:
@Override
public Optional<Trip> findById(String tripCanonicalName) {
StructuredQuery.PropertyFilter eqTripCanonicalName = StructuredQuery.PropertyFilter
.eq("canonicalName", tripCanonicalName);
EntityQuery query = Query.newEntityQueryBuilder().setKind("Trip")
.setFilter(eqTripCanonicalName).setLimit(1).build();
QueryResults<Entity> results = getDatastoreService().run(query);
if (results.hasNext()) {
return Optional.of(fromEntity(results.next()));
}
return Optional.empty();
}
这将获得实体 ( Trip
),无论其父 ( User
) 是谁。
---- 第二种选择 ----
在访问一个元素之前,您可能首先必须列出它们,然后选择一个并转到访问链接。正如我们所知,使用任务的 id 是不够的,因为它仅对其父级 ( User
) 是唯一的,而不是显示id
您可以使用 url 安全 id:
entity.getKey().toUrlSafe()
所以在从实体到对象的转换中,将Task
这个 id 编码为base-64 编码的元素分配。要从 url 安全使用中取回密钥
Key.fromUrlSafe
它将保证您将始终使用全局唯一 ID。
---- 第三种选择 ----
使用HATEOAS,您可以指定用于访问 的链接Task
,因此,如果任务有一些 id,例如parentId
oruserId
基本上是在获取他的父节点的 id,那么您可以很容易地建立一个指向这样的 url 的链接
http://base-url.com/users/ {userId}/tasks/{taskId}
因此,在 HATEOAS 请求中,这可以在链接中指示,指示元素允许的操作,因此查看元素使用self
,例如
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"userId": "my-traveler-user-id",
"_links":{
"self":{
"href":"http://localhost:8080/users/my-traveler-user-id/tasks/voyage-to-the-everest
}
}
}
如果您使用 a 而不是 auserId
您parentId
可以使用所有节点指定它们是否有父节点的接口来解决它。parent
使用定义整个父层次结构的属性甚至可以更灵活:
public interface DatastoreNode{
String getParentId();
String getParentKind();
String getParentUrlTag();
DatastoreNode getParent();
}
尽管强烈建议使用 HATEOAS,但您可以推断出具有 json 结构的相同 url,例如
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}