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等方法指定查询条件。
扩展阅读
官方文档[地址]
其它[地址]