我有Entity
看起来像这样:
@Entity
public class Relationship
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
@Basic
private UUID from;
@Basic
private UUID to;
}
现在我可以像这样拥有任意级别的间接:
final Relationship r0 = new Relationship(a,b);
final Relationship r1 = new Relationship(b,c);
final Relationship r2 = new Relationship(c,d);
final Relationship rN = new Relationship(d,e);
现在我希望尽可能高效地找到a
给我回复e
rN
N
级别为SQL
。
如果我经常写SELECT r.to
FROM relationship r
WHERE r.from = 'a' AND
r.to NOT IN ( SELECT r.from FROM relationship r)
,我会做类似跟随伪代码的事情:
List
我唯一可以在网上找到的是将Criteria.Builder.In
作为参数传递给Datastore
,但我没有列表,我需要使用子选择作为列出?
此外,这是使用Google App Engine中的Datastore
,并且仅限于通过JPA 2支持的某些内容。
我是否必须使用低级{{1}} API?
答案 0 :(得分:0)
在数据存储区中,没有办法发出单个查询来从'a'获取'e'。事实上,获得e的唯一方法是线性地单独查询每个关系,因此您需要进行四次查询。
您可以将列表作为参数传入,但这仅适用于IN
查询。 NOT IN
个查询不可用,JOIN
也没有。
(旁白:您可以使用from
和to
属性的组合来创建密钥,在这种情况下,您只需获取实体而不是查询。)
通常,GAE数据存储版本的服务是非规范化,即编写可以启用查询的额外数据。 (这很痛苦,因为它也意味着当你更新一个实体时,你需要小心更新非规范化数据,并且很难同步它 - 它专为网络类型流量设计,其中读取发生得更多经常比写。)
这是一个潜在的解决方案:
@Entity
public class Relationship
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
@Basic
private UUID from;
@Basic
private UUID to;
@ElementCollection
private Collection<UUID> reachable;
}
在这种情况下,您只需查询
WHERE from = 'a' and reachable = 'e'
答案 1 :(得分:0)
令人惊讶的是,即使有1000级间接,这种递归方法也不会出现StackOverflow错误,至少在本地开发服务器上是这样。
public UUID resolve(@Nonnull final UUID uuid)
{
final EntityManager em = EMF.TRANSACTIONS_OPTIONAL.createEntityManager();
try
{
final String qs = String.format("SELECT FROM %s a WHERE a.from = :from ", Alias.class.getName());
final TypedQuery<Alias> q = em.createQuery(qs, Alias.class);
q.setParameter("from", uuid);
final Alias r;
try
{
r = q.getSingleResult();
final Key tok = KeyFactory.createKey(Alias.class.getSimpleName(), r.getTo().toString());
if (em.find(Alias.class, tok) == null)
{
return r.getTo();
}
else
{
return this.resolve(r.getTo());
}
}
catch (final NoResultException e)
{
/* this is expected when there are no more aliases */
return uuid;
}
}
finally
{
em.close();
}
}
我所拥有的压力测试代码是在实际的GAE服务上超时,但我并不担心,我在实践中不会一次创建多个间接层。并且它不仅仅是一小部分间接,而且无论如何它都会在最终版本中被提升到Memcache
。