2010-02-17 22 views
16

我喜歡JPA中命名查詢的想法,我想要做靜態查詢,但我經常想從查詢的某個子集中獲取查詢的計數結果以及結果列表。我寧願不寫兩個幾乎相同的NamedQueries。理想情況下,我想擁有的是一樣的東西:有沒有辦法使用結果集來獲得JPA命名查詢的計數大小?

@NamedQuery(name = "getAccounts", query = "SELECT a FROM Account") 
. 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = q.getCount(); 

所以我們可以說,m爲10,s爲0,有400行的賬戶。我希望r有一個列表中的10個項目,但我想知道總共有400行。我可以寫一個第二@NamedQuery:

@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account") 

,但它似乎是一個幹違反這樣做,如果我永遠都只是會想計數。在這種簡單的情況下,很容易使兩者保持同步,但如果查詢發生變化,我不得不更新兩個@NamedQueries以使值保持一致。

這裏的常見用例是獲取某些子項,但需要某種方式指示總計數(「顯示400箇中的1-10個」)。

回答

13

因此,我最終使用的解決方案是創建兩個@NamedQuerys,一個用於結果集,另一個用於計數,但捕獲靜態字符串中的基本查詢以保持DRY並確保兩個查詢保持一致。因此,針對上述情況,我有這樣的:

@NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery) 
@NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery) 
. 
static final String accountQuery = " FROM Account"; 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue(); 

顯然,這個例子中,查詢的身體是微不足道,這是矯枉過正。但是,通過更復雜的查詢,您最終將得到查詢正文的單個定義,並可確保您同時查詢兩個查詢。您還可以獲得預編譯查詢的優勢,至少在Eclipselink中,您可以在啓動時獲得驗證,而不必在調用查詢時進行驗證。

通過執行兩個查詢之間的一致命名,可以包裝代碼的主體以僅基於查詢的基本名稱運行兩個集合。

+0

終於可以爲namedQueries工作了!謝謝 – Zavael 2014-06-26 08:39:13

+0

有趣的是,我甚至都不知道在配置註釋時你可以參考靜態決賽。然而,我認爲,不需要兩個單獨的命名查詢的解決方案仍然是理想的。 – aroth 2015-10-08 05:10:38

5

使用setFirstResult/setMaxResults返回結果集的一個子集,查詢甚至還沒有當你調用這些方法運行,它們會影響調用getResultList時將執行的生成SELECT查詢。如果您想獲得總記錄數,則必須在單獨的查詢中(通常在分頁之前)將SELECT COUNT您的實體存入。

有關完整示例,請查看Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs

+0

是。我想獲得查詢結果的完整計數。因此,該示例中的數不會對應於r.size(),或者我只會使用它。一個潛在的用例是我想獲得一個結果列表帳戶的結果頁面,但爲了讓他們總共有多少頁,我希望查詢的總數,即使我只是檢索25個結果。 – Tim 2010-02-18 01:10:02

+0

@Tim我澄清了我的答案。如果還不清楚,請告訴我。 – 2010-02-18 03:06:16

+0

謝謝。我試圖澄清我的問題。基本上,我知道修改器在運行之前更改查詢。我希望做的是有一個@NamedQuery,它作爲返回子集以及獲取計數的基礎,而不是爲計數寫一個查詢,爲返回集寫一個查詢。理想情況下仍然使用@NamedQuery。我會檢查你參考的鏈接。 – Tim 2010-02-19 16:32:37

1

哦,你可以用內省來獲得命名查詢註釋,如:

String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) { 
    NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class); 
    NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value(); 

    String code = null; 
    for (NamedQuery namedQuery : namedQueryAnnotations) { 
     if (namedQuery.name().equals(namedQueryKey)) { 
      code = namedQuery.query(); 
      break; 
     } 
    } 

    if (code == null) { 
     if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) { 
      code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey); 
     } 
    } 

    //if not found 
    return code; 
} 
+0

不知道這是如何適用於我的問題。我想使用NamedQuery來獲得預編譯,緩存和其他優化的好處。我希望兩個查詢是相同的,除了一個返回結果和一個返回一個計數。我想遵循DRY,而不是複製和粘貼條件子句。 – Tim 2011-06-30 16:17:07

相關問題