分組和聚合函數

您已經了解瞭如何向 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 的員工人數
高質量語言
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
標準API
CriteriaBuilder builder = session.getCriteriaBuilder();
critQuery.select(critQuery.from(Employee.class)).where(builder.lt(root.get("salary"), 10000));
Query<Employee> query = session.createQuery(critQuery);
List<Employee> results = query.getResultList();

其次,經常會出現需要動態構建查詢的情況。例如,您有一個過濾員工、公寓和任何內容的網頁。並且如果某些參數對用戶不重要,那麼他根本不指示它。因此,將 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 可以幫助您。就這樣吧。

可以在官方文檔中找到更多詳細信息。