分组和聚合函数

您已经了解了如何向 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 查询,那么 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 可以帮助您。就这样吧。

可以在官方文档中找到更多详细信息。