我对JPA 2很新,它是CriteriaBuilder / CriteriaQuery API:
CriteriaQuery
in the Java EE 6 tutorial
我想在没有实际检索它们的情况下计算CriteriaQuery的结果。这是可能的,我没有找到任何这样的方法,唯一的方法是这样做:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> cq = cb
.createQuery(MyEntityclass);
// initialize predicates here
return entityManager.createQuery(cq).getResultList().size();
这不是正确的方法......
有解决方案吗?
答案 0 :(得分:189)
类型为MyEntity
的查询将返回MyEntity
。您需要查询Long
。
CriteriaBuilder qb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
cq.select(qb.count(cq.from(MyEntity.class)));
cq.where(/*your stuff*/);
return entityManager.createQuery(cq).getSingleResult();
显然,您希望使用您在示例中跳过的任何限制和分组等来构建表达式。
答案 1 :(得分:29)
我使用cb.createQuery()(没有结果类型参数)对此进行了排序:
public class Blah() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery query = criteriaBuilder.createQuery();
Root<Entity> root;
Predicate whereClause;
EntityManager entityManager;
Class<Entity> domainClass;
... Methods to create where clause ...
public Blah(EntityManager entityManager, Class<Entity> domainClass) {
this.entityManager = entityManager;
this.domainClass = domainClass;
criteriaBuilder = entityManager.getCriteriaBuilder();
query = criteriaBuilder.createQuery();
whereClause = criteriaBuilder.equal(criteriaBuilder.literal(1), 1);
root = query.from(domainClass);
}
public CriteriaQuery<Entity> getQuery() {
query.select(root);
query.where(whereClause);
return query;
}
public CriteriaQuery<Long> getQueryForCount() {
query.select(criteriaBuilder.count(root));
query.where(whereClause);
return query;
}
public List<Entity> list() {
TypedQuery<Entity> q = this.entityManager.createQuery(this.getQuery());
return q.getResultList();
}
public Long count() {
TypedQuery<Long> q = this.entityManager.createQuery(this.getQueryForCount());
return q.getSingleResult();
}
}
希望有所帮助:)
答案 2 :(得分:22)
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
cq.select(cb.count(cq.from(MyEntity.class)));
return em.createQuery(cq).getSingleResult();
答案 3 :(得分:10)
由于其他人的答案是正确的,但过于简单,所以为了完整起见,我在下面的代码段中对复杂的 JPA条件查询执行SELECT COUNT
(有多个联接,提取,条件)。
略有修改this answer。
public <T> long count(final CriteriaBuilder cb, final CriteriaQuery<T> selectQuery,
Root<T> root) {
CriteriaQuery<Long> query = createCountQuery(cb, selectQuery, root);
return this.entityManager.createQuery(query).getSingleResult();
}
private <T> CriteriaQuery<Long> createCountQuery(final CriteriaBuilder cb,
final CriteriaQuery<T> criteria, final Root<T> root) {
final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
final Root<T> countRoot = countQuery.from(criteria.getResultType());
doJoins(root.getJoins(), countRoot);
doJoinsOnFetches(root.getFetches(), countRoot);
countQuery.select(cb.count(countRoot));
countQuery.where(criteria.getRestriction());
countRoot.alias(root.getAlias());
return countQuery.distinct(criteria.isDistinct());
}
@SuppressWarnings("unchecked")
private void doJoinsOnFetches(Set<? extends Fetch<?, ?>> joins, Root<?> root) {
doJoins((Set<? extends Join<?, ?>>) joins, root);
}
private void doJoins(Set<? extends Join<?, ?>> joins, Root<?> root) {
for (Join<?, ?> join : joins) {
Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
joined.alias(join.getAlias());
doJoins(join.getJoins(), joined);
}
}
private void doJoins(Set<? extends Join<?, ?>> joins, Join<?, ?> root) {
for (Join<?, ?> join : joins) {
Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
joined.alias(join.getAlias());
doJoins(join.getJoins(), joined);
}
}
希望它节省了一些人的时间。
因为IMHO JPA Criteria API不直观也不易阅读。
答案 4 :(得分:3)
这有点棘手,取决于您使用的JPA 2实现,这个适用于EclipseLink 2.4.1,但不适用于Hibernate,这里是EclipseLink的通用CriteriaQuery计数:
public static Long count(final EntityManager em, final CriteriaQuery<?> criteria)
{
final CriteriaBuilder builder=em.getCriteriaBuilder();
final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
countCriteria.select(builder.count(criteria.getRoots().iterator().next()));
final Predicate
groupRestriction=criteria.getGroupRestriction(),
fromRestriction=criteria.getRestriction();
if(groupRestriction != null){
countCriteria.having(groupRestriction);
}
if(fromRestriction != null){
countCriteria.where(fromRestriction);
}
countCriteria.groupBy(criteria.getGroupList());
countCriteria.distinct(criteria.isDistinct());
return em.createQuery(countCriteria).getSingleResult();
}
前几天我从EclipseLink迁移到Hibernate并且不得不将我的计数功能更改为以下内容,所以请随意使用,因为这是一个难以解决的问题,它可能不适用于您的情况,它已经在从Hibernate 4.x开始使用,请注意我不会尝试猜测哪个是根,而是我从查询中传递它以便解决问题,试图猜测太多模棱两可的角落情况:
public static <T> long count(EntityManager em,Root<T> root,CriteriaQuery<T> criteria)
{
final CriteriaBuilder builder=em.getCriteriaBuilder();
final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
countCriteria.select(builder.count(root));
for(Root<?> fromRoot : criteria.getRoots()){
countCriteria.getRoots().add(fromRoot);
}
final Predicate whereRestriction=criteria.getRestriction();
if(whereRestriction!=null){
countCriteria.where(whereRestriction);
}
final Predicate groupRestriction=criteria.getGroupRestriction();
if(groupRestriction!=null){
countCriteria.having(groupRestriction);
}
countCriteria.groupBy(criteria.getGroupList());
countCriteria.distinct(criteria.isDistinct());
return em.createQuery(countCriteria).getSingleResult();
}
答案 5 :(得分:1)
您也可以使用预测:
ProjectionList projection = Projections.projectionList();
projection.add(Projections.rowCount());
criteria.setProjection(projection);
Long totalRows = (Long) criteria.list().get(0);
答案 6 :(得分:0)
对于Spring Data Jpa,我们可以使用以下方法:
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#count(org.springframework.data.jpa.domain.Specification)
*/
@Override
public long count(@Nullable Specification<T> spec) {
return executeCountQuery(getCountQuery(spec, getDomainClass()));
}