Spring Data JPA:解析CriteriaQuery

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等方法指定查询条件。

 

扩展阅读

官方文档[地址]

其它[地址]

posted @ 2021-08-30 08:07  时空穿越者  阅读(4090)  评论(0编辑  收藏  举报