2011-03-18 88 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();