2013-12-14 24 views
0

我有一個Entity,看起來像這樣:在JPA 2中選擇最有效的方法?

@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其中rNN級別深。

如果我寫定期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但我不沒有清單,我需要使用子選擇作爲清單?

而且這是在谷歌App Engine的使用Datastore,它是對一些事情,它通過JPA 2.

支持難道我將不得不求助於低級別Datastore API的限制?

回答

0

在數據存儲中,無法發出單個查詢以從'a'獲取'e'。事實上,獲得e的唯一方法是單獨查詢每個關係,因此您需要執行四個查詢。

您可以將列表作爲參數傳入,但這僅適用於IN查詢。 NOT IN查詢不可用,也不是JOIN s。 (除此之外:您可以使用fromto屬性的組合來創建密鑰,在這種情況下,您只需獲取實體而不是查詢)。

通常情況下,GAE數據存儲版本的服務是非規範化的,也就是編寫額外的數據來啓用你的查詢。 (這是一個痛苦,因爲它也意味着當你更新一個實體時,你還需要小心地更新非規範化的數據,並且很難同步它 - 它被設計用於web類型的流量,其中讀取發生得更多經常比寫)

這是一個潛在的解決方案:

@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' 
+0

我研究過@ @CollectionCollection,並且我沒有看到這對我有什麼幫助,除非我去掉'to'屬性並且只在一個'Entity'上存儲一個別名'UUID'的列表,然後我有相反的問題,如果其中一個上游別名更改,我必須反向查找所有內容...... –

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

相關問題