2011-03-18 72 views
22

我正在爲我的系統中的實體實現「高級搜索」類功能,以便用戶可以使用多個條件(例如eq,ne,gt,lt等)來搜索該實體。關於這個實體的屬性。我使用JPA的Criteria API動態生成Criteria查詢,然後使用setFirstResult() & setMaxResults()來支持分頁。直到這一點都一切正常,但現在我想顯示結果網格上的結果總數,但我沒有看到一個簡單的方法來獲得標準查詢的總數。
這是我的代碼看起來像:使用JPA Criteria API進行分頁的總行數

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class); 
Root<Brand> from = cQuery.from(Brand.class); 
CriteriaQuery<Brand> select = cQuery.select(from); 
. 
. 
//Created many predicates and added to **Predicate[] pArray** 
. 
. 
select.where(pArray); 
// Added orderBy clause 
TypedQuery typedQuery = em.createQuery(select); 
typedQuery.setFirstResult(startIndex); 
typedQuery.setMaxResults(pageSize); 
List resultList = typedQuery.getResultList(); 

我的結果集可能是大的,所以我不希望加載我對數查詢實體,所以告訴我有效的方式來獲得總數像rowCount()方法上標準(我認爲它存在於Hibernate的標準中)。

回答

24

謝謝弗拉基米爾! 我把你的想法,並使用單獨的計數查詢來使用我現有的謂詞數組。最終實現看起來是這樣的:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class); 
Root<Brand> from = cQuery.from(Brand.class); 
CriteriaQuery<Brand> select = cQuery.select(from); 
. 
. 
//Created many predicates and added to **Predicate[] pArray** 
. 
. 
CriteriaQuery<Long> cq = builder.createQuery(Long.class); 
cq.select(builder.count(cq.from(Brand.class))); 
// Following line if commented causes [org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.enabled' [select count(generatedAlias0) from xxx.yyy.zzz.Brand as generatedAlias0 where (generatedAlias1.enabled=:param0) and (lower(generatedAlias1.description) like :param1)]] 
em.createQuery(cq); 
cq.where(pArray); 
Long count = em.createQuery(cq).getSingleResult(); 
. 
. 
select.where(pArray); 
. 
. 
// Added orderBy clause 
TypedQuery typedQuery = em.createQuery(select); 
typedQuery.setFirstResult(startIndex); 
typedQuery.setMaxResults(pageSize); 
List resultList = typedQuery.getResultList() 

雖然這是工作的罰款,但仍我不知道爲什麼我要寫

em.createQuery(cq); 

得到它的工作。任何想法?

+0

您是否能夠找出爲什麼您需要添加'em.createQuery(cq);'?謝謝 – Ittai 2011-12-22 07:01:32

+0

嘿,這正是我所需要的......我也想知道爲什麼這條線是必要的!? – 2013-02-28 14:15:44

+0

我懷疑這是因爲'Predicate's正在使用來自= cQuery.from(Brand.class)的'Root '這個部分的'Root <>'來構建,然後被用於這兩個計數查詢和分頁查詢。 AFAIK你需要使用'Root <>'對象兩次建立謂詞。第二個隱藏在這行'cq.select(builder.count(cq.from(Brand.class)));'中。爲什麼'em.createQuery(cq);'我不知道,IMO應該拋出一個異常。 – Neilos 2017-11-09 22:43:43

2

如果您使用Hibernate作爲您的JPA提供程序,請查看projections,尤其是Projections.rowCount()

雖然您可能需要執行兩次查詢,但是先獲取計數然後獲取結果。

請注意,對於普通的JPA,您可能需要其他方法。

+3

-1。 OP很清楚地表明他正在尋找關於「JPA Criteria API」的ansers,難道你不認爲你的回答有點誤導? (暗示hibernate預測是這樣做的方式)。我是這樣說的,因爲當我偶然發現問題時,我首先看到了你的答案,並且讓我誤以爲這就是方式(尤其是因爲你和下一個答案之間有一個加法,這使得你成爲唯一可見的答案)。 – Ittai 2011-12-21 06:54:31

+0

@Ittai,他提到Hibernate,甚至標記相應的問題... – Thomas 2011-12-21 07:59:10

+0

我認爲,當你讀到這個問題時,你會發現它不是關於休眠的,這只是很多時候你看到人們回答他們的問題認爲OP需要而不是OP請求。因爲如果你編輯你的問題似乎是一個誠實的錯誤,我會改變我的投票。 – Ittai 2011-12-21 09:10:17

14

爲什麼你不使用計數?

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Long> cQuery = builder.createQuery(Long.class); 
Root<Brand> from = cQuery.from(Brand.class); 
CriteriaQuery<Long> select = cQuery.select(builder.count(from)); 
. 
. 
//Created many predicates and added to **Predicate[] pArray** 
. 
. 
select.where(pArray); 
// Added orderBy clause 
TypedQuery<Long> typedQuery = em.createQuery(select); 
typedQuery.setFirstResult(startIndex); 
//typedQuery.setMaxResults(pageSize); 
// here is the size of your query 
Long result = typedQuery.getSingleResult();