直接在 CriteriaQuery.select() 設定欄位無效,因 JPA 預設回傳實體類型。分組查詢需明確構建 Tuple 或 DTO 投影。
@Repository
public interface CountryRepository extends JpaRepository<Country, Long> {
@Query("SELECT c.currency, SUM(c.population) FROM Country c " +
"WHERE :continent MEMBER OF c.continents " +
"GROUP BY c.currency HAVING COUNT(c) > 1")
List<Object[]> findCurrencyPopulationSummary(@Param("continent") String continent);
}
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<Country> root = query.from(Country.class);
// 選欄位:currency + SUM(population)
query.multiselect(
root.get("currency"),
cb.sum(root.get("population")).alias("totalPop")
);
// 條件:Europe 在 continents 集合中
query.where(cb.isMember("Europe", root.get("continents")));
// 分組與過濾
query.groupBy(root.get("currency"));
query.having(cb.gt(cb.count(root), 1));
// 執行
List<Tuple> results = entityManager.createQuery(query).getResultList();
results.forEach(t ->
System.out.println(t.get("currency") + " : " + t.get("totalPop"))
);
| JPQL | Criteria API | 說明 |
|---|---|---|
| SELECT a, SUM(b) | cb.sum(root.get("b")) | 聚合函數需透過 CriteriaBuilder |
| GROUP BY a | query.groupBy(root.get("a")) | 分組欄位必須出現在 select 中 |
| HAVING COUNT > 1 | query.having(cb.gt(cb.count(root), 1)) | 分組後過濾條件 |
| WHERE x MEMBER OF y | cb.isMember("x", root.get("y")) | 集合成員檢查 |