源碼
在Spring Data JPA相關的文章[地址]中提到了有哪幾種方式可以構建Specification的實例,該處需要借助CriteriaBuilder,回顧一下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);
解讀:
CriteriaBuilder用於根據特定條件限制查詢結果,請參見本文后面的示例。
CriteriaBuilder接口定義在包路徑javax.persistence.criteria下,代碼如下:
/** * Used to construct criteria queries, compound selections, * expressions, predicates, orderings. * * <p> Note that <code>Predicate</code> is used instead of <code>Expression<Boolean></code> * in this API in order to work around the fact that Java * generics are not compatible with varags. * * @since 2.0 */ public interface CriteriaBuilder {
類圖
方法定義
CriteriaBuilder中的一些方法如下圖所示:
解讀:
(1)CriteriaBuilder中的方法分為幾個類別,譬如:ordering、aggregate functions、subqueries、equality、comparisons等等。
(2)CriteriaBuilder中的方法的返回值主要有CriteriaQuery、Expression、Predicate等幾種類型。
示例
觀察CriteriaBuilder中and方法與or方法的定義,如下:
/** * Create a conjunction of the given boolean expressions. * @param x boolean expression * @param y boolean expression * @return and predicate */ Predicate and(Expression<Boolean> x, Expression<Boolean> y); /** * Create a conjunction of the given restriction predicates. * A conjunction of zero predicates is true. * @param restrictions zero or more restriction predicates * @return and predicate */ Predicate and(Predicate... restrictions); /** * Create a disjunction of the given boolean expressions. * @param x boolean expression * @param y boolean expression * @return or predicate */ Predicate or(Expression<Boolean> x, Expression<Boolean> y); /** * Create a disjunction of the given restriction predicates. * A disjunction of zero predicates is false. * @param restrictions zero or more restriction predicates * @return or predicate */ Predicate or(Predicate... restrictions);
解讀:
上述and方法與or方法用於組合多個查詢條件。
其中Predicate and(Predicate... restrictions);方法接受不定數參數Predicate... restrictions,故可以傳入多個Predicate參數,最佳實踐是傳入一個數組;其意義是用and連接詞將多個條件連接起來。
具體案例——添加多個查詢條件
private Specification createSpecification(Integer specialId, String specialEmail) { Specification<User> specification = new Specification<>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path id = root.get("id"); Predicate predicateId = cb.gt(id, specialId); Path email = root.get("email"); Predicate predicateEmail = cb.equal(email, specialEmail); return cb.and(predicateId, predicateEmail); } }; return specification; }
解讀:
上述着色處代碼以and方法將兩個條件組合在一起
擴展閱讀
JPA Criteria Queries[地址]
Predicate與Expression
從前面的分析可知,CriteriaBuilder中的很多方法接受Expression或者Predicate類型的參數,並返回Expression或者Predicate類型的結果,譬如上面提到的and方法,所以本小節來探尋一下Expression與Predicate之間的關系。
Expression與Predicate之間的關系如下圖所示:
解讀:
Predicate接口繼承了Expression接口,所以CriteriaBuilder中接受Expression類型參數的方法(譬如:and方法等)可以接受Predicate類型的參數,正如前面示例所展示的那樣。
Note:
Path接口也繼承了Expression接口,所以CriteriaBuilder中接受Expression類型參數的方法(譬如:lt方法)可以接受Path類型實例:
Specification<User> specification = new Specification<>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path<Integer> path = root.get("id"); return cb.lt(path, id); } };
解讀:
上述示例在構造了Path類型的變量后調用了lt方法,該方法的定義如下:
/** * Create a predicate for testing whether the first argument is * less than the second. * @param x expression * @param y value * @return less-than predicate */ Predicate lt(Expression<? extends Number> x, Number y);