CriteriaQuery

原始碼定義

CriteriaQuery定義在包路徑javax.persistence.criteria下,其定義如下:

/**
* The <code>CriteriaQuery</code> interface defines functionality that is specific
* to top-level queries.
*
* @param <T> the type of the defined result
*
* @since 2.0
*/
public interface CriteriaQuery<T> extends AbstractQuery<T> {

類圖

CriteriaQuery對應的類圖如下:

方法定義

此處聚焦CriteriaQuery繼承體系中定義了哪些方法,請參見下圖:

解讀:

根據上述方法的返回值可知,AbstractQuery、CriteriaQuery介面中的方法大部分是返回其本身型別變數,可以理解為流式API的寫法。

實際應用

回顧一下Specification中toPredicate方法的定義,程式碼如下:

    /**
* Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
* {@link Root} and {@link CriteriaQuery}.
*
* @param root must not be {@literal null}.
* @param query must not be {@literal null}.
* @param criteriaBuilder must not be {@literal null}.
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

解讀:

上述方法的第二個引數為CriteriaQuery型別,所以在構建Specification的例項(實現其toPredicate方法)時可以藉助CriteriaQuery的能力,案例如下:

  public Page<User> getUsers(Integer id, Integer pageNum, Integer pageSize) {
Sort sort = Sort.by(Sort.Direction.DESC, "id");
Pageable pageable = PageRequest.of(pageNum, pageSize, sort); Specification<User> specification = new Specification<>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Integer> idPath = root.get("id"); query.where(cb.lt(idPath, id));
query.orderBy(cb.asc(idPath)); return query.getRestriction();
}
};
return userRepository.findAll(specification, pageable);
}

解讀:

上述案例呼叫了CriteriaQuery的where以及orderBy方法以指定具體查詢條件,在return語句中呼叫了CriteriaQuery的getRestriction方法。

Note:

從前面類圖可知,getRestriction方法實際上是定義在CommonAbstractCriteria介面中,程式碼如下:

/**
* The <code>CommonAbstractCriteria</code> interface defines functionality
* that is common to both top-level criteria queries and subqueries as
* well as to update and delete criteria operations.
* It is not intended to be used directly in query construction.
*
* <p> Note that criteria queries and criteria update and delete operations
* are typed differently.
* Criteria queries are typed according to the query result type.
* Update and delete operations are typed according to the target of the
* update or delete.
*
* @since 2.1
*/
public interface CommonAbstractCriteria { /**
* Create a subquery of the query.
* @param type the subquery result type
* @return subquery
*/
<U> Subquery<U> subquery(Class<U> type); /**
* Return the predicate that corresponds to the where clause
* restriction(s), or null if no restrictions have been
* specified.
* @return where clause predicate
*/
Predicate getRestriction(); }

CriteriaQuery與EntityManager

EntityManager定義在包路徑javax.persistence下,其中的一些方法如下圖所示:

解讀:

EntityManager提供了眾多createQuery方法,其中一個createQuery方法可以接受CriteriaQuery型別的引數,該方法的定義如下:

    /**
* Create an instance of <code>TypedQuery</code> for executing a
* criteria query.
* @param criteriaQuery a criteria query object
* @return the new query instance
* @throws IllegalArgumentException if the criteria query is
* found to be invalid
* @since 2.0
*/
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery);

示例

  private void getUserList(String specialEmail) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class); Root<User> root = query.from(User.class); Path<User> email = root.get("email");
Predicate predicateEmail = cb.equal(email, specialEmail);
query.where(predicateEmail); TypedQuery<User> q = entityManager.createQuery(query);
List<User> result = q.getResultList();
for (User user : result) {
//列印查詢結果
System.out.println(user.toString());
}
}

解讀:

上述程式碼通過EntityManager的getCriteriaBuilder方法獲取了CriteriaBuilder型別的變數,進而構建了CriteriaQuery型別的變數,然後進一步利用CriteriaQuery中的from、where等方法指定查詢條件。

擴充套件閱讀

官方文件[地址]

其它[地址]