20240912 Spring Data JPA Criteria原生複雜查詢與Join寫法
若基於各種原因(系統穩定度或其他考量),不想給Spring Boot安裝QueryDSL,
其實Criteria就有內建複雜查詢的功能,不用再回去寫JPQL
代碼
註:這邊稍微偷懶簡化架構沒有儲藏庫
JpaSpecificationExecutor<>
!!
DAO 快去繼承@Repository
public interface XxxDao extends JpaRepository<XxxPO, Integer>, JpaSpecificationExecutor<XxxPO> {
}
Service
// java
// 複雜查詢規格拼裝
Specification<XxxPO> spec = (root, query, builder) -> {
List<Predicate> predicates = new ArrayList<>();
Join<XxxPO, XyyPO> xyJoin = root.join("XyyPO", JoinType.LEFT);
if (yId != null) {
predicates.add(builder.equal(xyJoin.get("yId"), yId));
}
if (StringUtils.isNotBlank(xKind)) {
predicates.add(builder.equal(xyJoin.get("xKind"), xKind));
}
return query.getRestriction();
};
// 使用複雜查詢規格查詢
List<XxxPO> xxxPO = XxxDAO.findAll(spec);
Murmur Time
JPQL純語句可能也不是很好維護?不過程式碼是最少的,設置好後只管調用就行
^^;;
Expression跟Path是父跟子的繼承關係,不過就是意義上不太一樣,雖然都能用就是
上面的例子甚至懶得接值丟進builder引發一個想法:這種情境Java 17用var接值會是甚麼?<-應該會是他本來要Return的東西
不管是用root的get()方法,還是Join類,都是Path,不過坊間蠻多人用Expression接
//java <Y> Path<Y> get(String attributeName);
有些人是先
query.where(builder.and(predicates.toArray(new Predicate[0])));
再return query.getRestriction();
,有些人是簡化成return builder.and(predicates.toArray(new Predicate[0]));
builder就是CriteriaBuilder,query就來自builder,root來自query,如果不用Specification寫法會長這樣
//java // 某Repository @PersistenceContext private EntityManager entityManager; // 某個複雜查詢方法體 CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<ChannelSellingProductPO> query = builder.createQuery(XxxPO.class); Root<ChannelSellingProductPO> root = query.from(XxxPO.class); // ry
所以上一點提到
return builder.and(predicates.toArray(new Predicate[0]));
還可以再退化成query.select(root).where(predicates.toArray(new Predicate[0]));
- 搭配
entityManager.createQuery(query).getResultList();
就不用XxxDAO.findAll(spec);
,會直接得到查詢結果
- 搭配
感受到這個Lambda簡化很多事情吧~~