24

有两种实体:User 和 Trip。用户是 Trip 的父级,而 Trip 是 User 的子级。

出于隐私考虑,我只发布旅行 ID/名称。因为它看起来像旅行密钥包含编码的用户 ID/名称。

如果父键未知,如何通过 ID/名称获取实体?

4

5 回答 5

19

你不能。父键是实体键的一部分,您需要一个完整的键来获取实体。

除非您指定祖先键,否则使用键过滤器查询也不会找到具有父级的实体。

于 2013-01-13T10:36:39.883 回答
1

如果您在“根”实体下创建所有“用户”实体并向“旅行”实体添加“uuid”属性,则可以查找具有指定 UUID 的单个“旅行”。

Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
于 2013-07-25T06:49:42.453 回答
0

@peter-knego 在最初的问题中:用户是 Trip 的父母。要通过 id 获取实体,您需要使用父项重建密钥以获取完整密钥。但是您可以避免这种情况,只需为 Trip 的完整密钥分配 id。您可以使用分配的 id 构造完整的密钥。这是我的逻辑。

于 2013-01-15T10:01:24.593 回答
0

你可以这样做:

public Entity GetEntity(String kind, String idName) 
        throws EntityNotFoundException{
    Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
    return datastore.get(key);
}
于 2013-09-29T18:54:08.070 回答
0

我制定了 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,例如parentIdoruserId基本上是在获取他的父节点的 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 而不是 auserIdparentId可以使用所有节点指定它们是否有父节点的接口来解决它。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: {}  
       }
    }
于 2017-05-03T23:35:59.463 回答