2013-01-13 39 views
21

有两种实体:User和Trip。用户是旅行的父母,旅行是用户的子女。Google App Engine数据存储:如果父密钥未知,如何通过ID /名称获取实体?

为了保护隐私,我仅发布旅程ID /姓名。因为它看起来像一个Trip Key包含编码的用户ID /名称。

如何通过ID /名称获取实体(如果父密钥未知?

+2

+1相同的URL - 这是一个完全有效的问题。谁把-1 - 关心解释? –

+1

为什么你不使用搜索? [see] [1] [1]:http://stackoverflow.com/questions/12675664/create-a-good-looking-url-for-a-key-with-ancestors/12676004#comment17106761_12676004 –

+1

@ Lapteuh - 你甚至看过你提到的答案吗?他们提出的查询需要完整的父键(kind + id/name),这正是OP没有的。 –

回答

17

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

此外,query with key filter将不会找到具有父母的实体,除非您指定祖先密钥。

0

@ peter-knego第一个问题:用户是Trip的父母。要通过id获取实体,您需要使用父级重建密钥来获取完整密钥。但是,您可以避免这种情况,只需为Trip的全部密钥分配ID。你可以用分配的ID构造完整的密钥。这是我的逻辑。

1

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

Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString()); 
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter); 
0

你可以做这样的事情:

public Entity GetEntity(String kind, String idName) 
     throws EntityNotFoundException{ 
    Key key = KeyFactory.createKey(kind, Long.parseLong(idName)); 
    return datastore.get(key); 
} 
+1

不,它不会找到任何东西,除非你在'key'中指定父项。 –

0

我工作了3个替代品可以解决这个问题,这是一个非常重要的恕我直言。

----第一备选物----

如果你旅行的ID从其他属性计算,有一种方法。而不是通过其id得到Trip从其他计算属性中获取它。让我们想象你的Trip的id是用一些规范的名字来计算的(例如你可以从它的完整标题中推断出一个URN),例如如果旅行的全名是

航程珠峰

您的规范名称可能是voyage-to-the-everest,这是你作为名称使用的密钥字符串。因此,而不是使用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 encode。从网址获取密钥的安全使用

Key.fromUrlSafe 

它会保证你将永远使用全球唯一的ID。

----第三替代----

使用HATEOAS你可以指定链接accesing的Task,所以如果该任务有一定的ID,如parentIduserId它基本上让他的父母节点的ID,也可能是很容易让你在HATEOAS要求,这可能因此stablish一个链接指向一个URL这样

http://base-url.com/users/ {} userId的/任务/ {}任务id

在链接中指示,表示该元素的允许的操作,所以用于查看元素使用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 
    } 
    } 
} 

如果不是一个userId您使用parentId你可以做出来一个接口,所有节点指定它们是否具有父项。即使它可能是与在其中定义整个父层次一个parent属性更加灵活:

public interface DatastoreNode{ 
    String getParentId(); 
    String getParentKind(); 
    String getParentUrlTag(); 
    DatastoreNode getParent(); 
} 

虽然HATEOAS强烈建议你可以推断出有一个JSON结构,如

{ 
     "id": "voyage-to-the-everest", 
     "name":"Voyage to the Everest", 
     "parent": { 
      parentKind: "User", 
      parentId: "my-traveler-user-id", 
      parentUrlTag: "users", 
      parent: {} 
     } 
    } 
相关问题