# 在 Spring Data JPA 下使用 Criteria API ###### tags: `Spring` `java` `jpa` `persistence` 在實際應用中,資料查詢的條件常常是多變性的,也就是無法100%完全預測使用者所下的限制,所以得使用 [Criteria API](https://javaee.github.io/tutorial/persistence-criteria.html) 以滿足<ruby>動<rt>ㄍㄜˋ</rt></ruby><ruby>態<rt>ㄓㄨㄥˇ</rt></ruby><ruby>搜<rt>ㄕㄞ</rt></ruby><ruby>尋<rt>ㄒㄩㄢˇ</rt></ruby><ruby>條<rt>ㄒㄩ</rt></ruby><ruby>件<rt>ㄑㄧㄡˊ</rt></ruby>。首先 repository 得繼承 ```JpaSpecificationExecutor<T>```<sup>[JavaDoc](https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html)</sup> ``` @Repository public interface SomeoneRepository extends JpaRepository<Someone, Long>, JpaSpecificationExecutor<Someone> { } ``` 使其支援 * ```public long count(Specification<T> spec)``` 根據 ```Specification``` 回傳符合的資料集數量。 * ```public List<T> findAll(Specification<T> spec)``` 根據 ```Specification``` 回傳符合的資料集。 * ```public Page<T> findAll(Specification<T> spec, Pageable pageable)``` 根據 ```Specification``` 及 `Pageable` 回傳符合的資料 ```Page```。 * ```public List<T> findAll(Specification<T> spec, Sort sort)``` 根據 ```Specification``` 及```Sort``` 回傳符合的資料集。 * ```public Optional<T> findOne(Specification<T> spec)``` 根據 ```Specification``` 回傳符合的資料,若沒有符合的資料則回傳 ```Optional.empty()```。 等 methods。```Page```、```Pageable```請參考此[筆記](https://hackmd.io/@LeeLo/),那什麼是```Specification```呢? ## 建立 Specification ```public final class SomeoneSpecifications { private SomeoneSpecifications() { } /** * @param nicknames 模糊查詢-會員名稱 * @param tages 查詢-會員名稱 * @return */ public static Specification<Someone> likeNickname(Set<String> nicknames, Set<String> tages) { return new Specification<Someone>() { @SuppressWarnings("FieldNameHidesFieldInSuperclass") private static final long serialVersionUID = 6644524130903161741L; @Override public Predicate toPredicate(Root<Someone> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { Set<Predicate> set = new HashSet<>(); for (String nickname : nicknames) { //使用 like 模糊查詢會員名稱 set.add(criteriaBuilder.like(root.get("nickname"), "%" + nickname + "%")); } if (!tages.isEmpty()) { //使用 in 查詢資料 set.add(root.get("nickname").in(tages)); } Predicate[] predicates = new Predicate[set.size()]; predicates = set.toArray(predicates); return criteriaBuilder.or(predicates); } }; } } ``` ## 實作的 Method 參數介紹 * [Root](https://www.objectdb.com/api/java/jpa/criteria/Root) * 需要查詢的 Enitity * [CriteriaQuery](https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaQuery.html) * 用來創建一個查詢對象 * [CriteriaBuilder](https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html) * 可以實作 SQL 的條件式(and, or, equal, like, in,....) ## 在 Controller 可以在 Repository 呼叫 Specifications class method ``` someoneRepository.findAll(SomeoneSpecifications.likeNickname(titles, tags); ``` ## 參考來源 > https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-four-jpa-criteria-queries/ > https://developer.ibm.com/articles/j-typesafejpa/ > https://javaee.github.io/tutorial/toc.html