分组和聚合函数
您已经了解了如何向 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 的员工人数 |
---|
高质量语言 |
|
标准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 可以帮助您。就这样吧。
可以在官方文档中找到更多详细信息。