12

次の便利なメソッドを実装しようとしています。

/**
 * Counts the number of results of a search.
 * @param criteria The criteria for the query.
 * @return The number of results of the query.
 */
public int findCountByCriteria(CriteriaQuery<?> criteria);

Hibernate では、これは

criteria.setProjection(Projections.rowCount());

JPAで上記に相当するものは何ですか? 単純なカウントの例を多数見つけましたが、行数を決定する必要がある CriteriaQuery を使用しているものはありませんでした。

編集:

残念ながら、@ Pascalの答えは正しいものではないことがわかりました。問題は非常に微妙で、結合を使用する場合にのみ現れます。

// Same query, but readable:
// SELECT *
// FROM Brain b
// WHERE b.iq = 170

CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> root = query.from(Person.class);
Join<Object, Object> brainJoin = root.join("brain");
Predicate iqPredicate = cb.equal(brainJoin.<Integer>get("iq"), 170);
query.select(root).where(iqPredicate);

を呼び出すfindCountByCriteria(query)と、次の例外で終了します。

org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.iq' [select count(generatedAlias0) from xxx.tests.person.dom.Person as generatedAlias0 where generatedAlias1.iq=170]

そのような方法を提供する他の方法はありますCountByCriteriaか?

4

7 に答える 7

18

それを行うためのユーティリティ クラス JDAL JpaUtils を作成しました。

  • カウント結果: Long count = JpaUtils.count(em, criteriaQuery);
  • CriteriaQueries をコピー: JpaUtils.copyCriteria(em, criteriaQueryFrom, criteriaQueryTo);
  • カウント基準を取得: CriteriaQuery<Long> countCriteria = JpaUtils.countCriteria(em, criteria)

等々...

ソース コードに興味がある場合は、JpaUtils.javaを参照してください。

于 2012-02-12T04:11:15.560 に答える
5

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();
    }
}

それが役に立てば幸い :)

私がやったことは、CriteriaBuilderのビルダーのようなもので、クエリを作成して、同じ基準制限でlist()またはcount()を呼び出すことができます。

于 2012-05-11T19:03:17.757 に答える
3

上記の解決策はいずれも EclipseLink 2.4.1 では機能しません。すべてデカルト積 (N^2) のカウントで終了しました。ここに EclipseLink の小さなハックがあります。唯一の欠点は、次の場合に何が起こるかわからないことです。 FROM 複数のエンティティを選択している場合、CriteriaQuery の最初に見つかったルートからカウントしようとしますが、このソリューションは Hibernate では機能しません (JDAL は機能しますが、JDAL は EclipseLink では機能しません)。

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();
  }
于 2012-11-21T09:59:18.540 に答える
2

このようなものをお探しですか?

/**
 * Counts the number of results of a search.
 * 
 * @param criteria The criteria for the query.
 * @return The number of results of the query.
 */
public <T> Long findCountByCriteria(CriteriaQuery<?> criteria) {
    CriteriaBuilder builder = em.getCriteriaBuilder();

    CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
    Root<?> entityRoot = countCriteria.from(criteria.getResultType());
    countCriteria.select(builder.count(entityRoot));
    countCriteria.where(criteria.getRestriction());

    return em.createQuery(countCriteria).getSingleResult();
}

次のように使用できます。

// a search based on the Criteria API
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> personRoot = criteria.from(Person.class);
criteria.select(personRoot);
Predicate personRestriction = builder.and(
    builder.equal(personRoot.get(Person_.gender), Gender.MALE),
    builder.equal(personRoot.get(Person_.relationshipStatus), RelationshipStatus.SINGLE)
);
criteria.where(personRestriction);
//...

// and to get the result count of the above query
Long count = findCountByCriteria(criteria);

PS:これがこれを実装する正しい/最良の方法であるかどうかはわかりませんが、まだCriteria APIを学んでいます...

于 2010-10-22T17:59:13.397 に答える
0

基準クエリの全体的な考え方は、厳密に型指定されているということです。したがって、生の型を使用している各ソリューション (CriteriaQuery または Root または Root のジェネリックなし) - これらのソリューションは、その主なアイデアに反しています。私はちょうど同じ問題に遭遇し、「適切な」方法で(JPA2とともに)解決するのに苦労しています。

于 2012-09-19T07:45:07.187 に答える
-3

私は休止状態と基準APIでそのようなことをします

public Long getRowsCount(List<Criterion> restrictions ) {
       Criteria criteria = getSession().createCriteria(ThePersistenclass.class);
       for (Criterion x : restrictions)
             criteria.add(x);
   return criteria.setProjection(Projections.rowCount()).uniqueResult();        

}

助けてほしい

于 2011-09-13T16:35:17.170 に答える