分組和聚合函數
您已經了解瞭如何向 Criteria API 發出簡單請求。讓我們看看如何進行更複雜的查詢。
例如,我們要編寫一個查詢來確定一家公司的員工人數。下面是它在 HQL 中的樣子:
select count(*) from Employee
在 Criteria API 上像這樣:
CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));
完整的 Java 代碼如下所示:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));
Query<Long> query = session.createQuery(critQuery);
Long count = query.getSingleResult();
使用 HQL 也是一樣的:
String hqlQuery = "select count(*) from Employee";
Query<Long> query = session.createQuery(hqlQuery);
Long count = query.getSingleResult();
現在讓我們嘗試計算公司的平均工資。HQL 查詢將如下所示:
select avg(salary) from Employee
在 Criteria API 上像這樣:
CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));
完整的 Java 代碼如下所示:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));
Query<Double> query = session.createQuery(critQuery);
Double avgSalary = query.getSingleResult();
標準更新
修改表就像從表中獲取數據一樣簡單。為此,CriteriaBuilder 有一個特殊的方法 - createCriteriaUpdate(),它創建一個對象條件更新<T>更新數據庫中的實體。
給不到1萬的員工漲工資吧。下面是這個 HQL 查詢的樣子:
update Employee set salary = salary+20000 where salary<=10000
這就是它在 Criteria API 上的樣子:
CriteriaUpdate<Employee> criteriaUpdate = builder.createCriteriaUpdate(Employee.class);
Root<Employee> root = criteriaUpdate.from(Employee.class);
criteriaUpdate.set("salary", "salary+20000");
criteriaUpdate.where(builder.lt(root.get("salary"), 10000));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();
條件刪除
刪除記錄甚至比更改記錄更容易。為此,有一個特殊的方法createCriteriaDelete(),它創建一個對象條件刪除<T>.
讓我們把沒有價值的員工都砍掉:他們的工資不到一萬。下面是這個 HQL 查詢的樣子:
delete from Employee where salary<=10000
這就是它在 Criteria API 上的樣子:
CriteriaDelete<Employee> criteriaDelete = builder.createCriteriaDelete(Employee.class);
Root<Employee> root = criteriaDelete.from(Employee.class);
criteriaDelete.where(builder.lt(root.get("salary"), 10000));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();
標準 API 的優勢
那麼 Criteria API 有什麼好處呢?查詢繁瑣,HQL肯定會更緊湊。
首先,如果您需要將參數傳遞給它們,HQL 查詢就不會那麼短。比較:
我們考慮工資低於 10,000 的員工人數 |
---|
高質量語言 |
|
標準API |
|
其次,經常會出現需要動態構建查詢的情況。例如,您有一個過濾員工、公寓和任何內容的網頁。並且如果某些參數對用戶不重要,那麼他根本不指示它。因此,將 null 傳遞給服務器。
這是你的任務:選擇具有特定職業(occupation)、薪水(salary)和工作年份(YEAR(join_date))的員工。但是,如果任何參數值為空,則不要在過濾器中使用它。
然後 HQL 查詢將如下所示:
from Employee
where (occupation = :ocp)
and (salary = :sal)
and ( YEAR(join_date) = :jny)
但它不會正常工作,因為我們希望如果“jny”參數為空,那麼請求將如下所示:
from Employee
where (occupation = :ocp)
and (salary = :sal)
我們可以嘗試通過檢查參數是否為 null 來重寫請求,然後我們將得到如下內容:
from Employee
where (occupation = :ocp or :ocp is null)
and (salary = :sal or :sal is null)
and ( YEAR(join_date)= :jny or :jny is null)
看看現實如何變得更加複雜?現實往往是這樣的:)
但是過濾器可能更複雜。如何搜索任務中包含“購買”一詞的用戶?或者有逾期任務的用戶?
from Employee
where (occupation = :ocp)
and (salary = :sal)
and (YEAR(join_date) = :jny)
and (tasks.name like '%buy%')
and (tasks.deadline < curdate())
如果您在此類查詢的某處寫入or is null,則這不會取消表之間的連接。
所以在實踐中,當您對多個表的字段進行任何復雜的篩選時,Criteria API 可以幫助您。就這樣吧。
可以在官方文檔中找到更多詳細信息。
GO TO FULL VERSION