1. 概述
在日常开发中,我们经常会遇到需要根据某个属性是否属于给定集合来查询实体的需求。
本文将介绍如何使用 Criteria API 来优雅地解决这类问题。
2. 示例实体类
先来看一下我们将用到的两个实体类。
首先是一个 DeptEmployee
类,它与 Department
类之间是 多对一关系:
@Entity
public class DeptEmployee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String title;
@ManyToOne
private Department department;
}
然后是 Department
实体,对应多个 DeptEmployee
:
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String name;
@OneToMany(mappedBy="department")
private List<DeptEmployee> employees;
}
3. 使用 CriteriaBuilder.In
我们可以通过 CriteriaBuilder
接口来构建 IN 查询。
✅ **关键点:in()
方法接收一个 Expression
,并返回一个新的 CriteriaBuilder.In
类型的 Predicate
**。
CriteriaQuery<DeptEmployee> criteriaQuery =
criteriaBuilder.createQuery(DeptEmployee.class);
Root<DeptEmployee> root = criteriaQuery.from(DeptEmployee.class);
In<String> inClause = criteriaBuilder.in(root.get("title"));
for (String title : titles) {
inClause.value(title);
}
criteriaQuery.select(root).where(inClause);
这段代码手动为每个值调用了 .value()
,适合动态构造 IN 条件。
4. 使用 Expression.In
另一种方式是使用 Expression
接口提供的 in()
方法重载版本:
criteriaQuery.select(root)
.where(root.get("title")
.in(titles));
⚠️ 注意:与 CriteriaBuilder.in()
不同,Expression.in()
直接接受一个集合参数,写法更简洁。
5. 子查询中的 IN 表达式
前面的例子都是基于固定值集合。现在我们来看一个使用子查询生成集合的场景。
比如我们要找出所有所属部门名称包含特定关键字的员工:
Subquery<Department> subquery = criteriaQuery.subquery(Department.class);
Root<Department> dept = subquery.from(Department.class);
subquery.select(dept)
.distinct(true)
.where(criteriaBuilder.like(dept.get("name"), "%" + searchKey + "%"));
criteriaQuery.select(emp)
.where(criteriaBuilder.in(emp.get("department")).value(subquery));
这里我们创建了一个子查询,并把它作为表达式传入 .value()
中,用于查找匹配的 Department
实体。
6. 总结
在这篇文章中,我们学习了使用 Criteria API 实现 IN 查询的不同方式:
- 使用
CriteriaBuilder.In
手动添加值 - 使用
Expression.in()
简洁传入集合 - 结合子查询实现动态 IN 查询
📌 最终完整代码可以在 GitHub 上获取:https://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate-jpa