Spring Data JPA系列QueryByExampleExecutor使用详解
简介
Spring Data JPA 是 Spring Data 的一个模块,它通过 JPA 技术为程序开发人员提供了方便、快捷的持久化支持。Query By Example(QBE)是 Spring Data JPA 模块中的一部分,允许您根据已知的实体对象创建查询样例,可以通过 QBE 生成基于实体属性的动态查询语句。
QueryByExampleExecutor
QueryByExampleExecutor 接口提供了按实例的查询语法。该接口包含两个方法:
<S extends T> Optional<S> findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);
其中,findOne() 方法将返回与示例符合的第一个实体。如果没有找到任何实体,则返回 Optional 的空实例。
findAll() 方法将根据示例返回一个 Iterable 集合。如果没有找到任何实体,则返回空的 Iterable 实例。
ExampleMatcher
ExampleMatcher 是 Query By Example 的核心部分,它描述了对特定类型的示例应如何进行匹配。 ExampleMatcher 可以在 Query 接口级别或在基础 CRUD Repository 接口级别对应用程序执行的查询进行全局配置。
ExampleMatcher.Builder 是用于实例化 ExampleMatcher 的静态构建器。
以下代码片段说明了如何构建 ExampleMatcher 对象:
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("field1", "field2")
.withMatcher("field3", matcher -> matcher.startsWith())
.withMatcher("field4", matcher -> matcher.endsWith())
.withMatcher("field5", matcher -> matcher.contains())
.withMatcher("field6", matcher -> matcher.matches());
上述 ExampleMatcher 会执行以下操作:
- 忽略名为 field1 和 field2 的属性。
- 特定字段应以其字段值开头筛选。
- 特定字段应以其字段值结尾。
- 特定字段应包含其字段值。
- 特定字段应具有与其字段值完全匹配的值。
示例1 方法级别
考虑以下 Entity:
@Entity
@Table(name = "employee")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id", nullable = false)
private Department department;
// ... 省略其他字段和方法
}
现在我们想按名称模糊搜索 Employee,请使用 QBE 实现此目的。
Employee employee = new Employee();
employee.setName("mark");
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("name", match -> match.contains());
Example<Employee> example = Example.of(employee, matcher);
List<Employee> employees = employeeRepository.findAll(example);
上面的示例将返回符合 name 属性包含“mark”子字符串的 Employee 实例的所有结果。请注意,我们使用的是 Example 类的 of() 工厂方法来创建 Example 实例。
示例2 Query 接口级别
考虑以下 Employee Entity:
@Entity
@Table(name = "employee")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id", nullable = false)
private Department department;
// ... 省略其他字段和方法
}
现在我们想按部门名称以及部门经理姓名搜索 Employee,请使用 QBE 实现此目的。
首先,我们需要创建一个自定义的查询接口,这将包含我们要使用的自定义查询方法。
public interface EmployeeRepositoryCustom {
List<Employee> findByDepartmentAndManager(String departmentName, String managerName);
}
其次,我们需要创建一个实现,它将包含我们要使用的自定义查询方法的查询方法。
@Repository
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Employee> findByDepartmentAndManager(String departmentName, String managerName) {
Department department = new Department();
department.setName(departmentName);
Employee manager = new Employee();
manager.setName(managerName);
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("id")
.withMatcher("name", match -> match.contains());
Example<Employee> example = Example.of(manager, matcher);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
Root<Employee> root = query.from(Employee.class);
Join<Employee, Department> join = root.join("department");
query.select(root)
.where(criteriaBuilder.equal(join.get("name"), department.getName()),
criteriaBuilder.equal(root.get("manager"), manager));
return entityManager.createQuery(query).getResultList();
}
}
这将对名为“departmentName”的部门以及名为“managerName”的经理进行搜索。这里我们将经理实例自己创建 Example,以便可以将 Example 用于其名称。我们同时使用 QueryDSL Lambda 表达式和 JPA CriteriaBuilder 构建搜索条件和搜索结果。
最后,我们需要创建 CRUD Repository 接口和实体的 Repository 实现类。
@Transactional(readOnly = true)
public interface EmployeeRepository extends JpaRepository<Employee, Long>, QueryByExampleExecutor<Employee>, EmployeeRepositoryCustom {
}
@Repository
@Transactional(readOnly = true)
public class EmployeeRepositoryImpl extends SimpleJpaRepository<Employee, Long> implements EmployeeRepository {
public EmployeeRepositoryImpl(EntityManager em) {
super(Employee.class, em);
}
}
现在,我们可以在我们的应用程序中调用我们的函数,并且将返回当前按照特定条件过滤的搜索结果集。
List<Employee> employees = employeeRepository.findByDepartmentAndManager("IT", "Mark");
总结
这篇文档介绍了 Spring Data JPA Query By Example Executor 和 ExampleMatcher 接口的细节。QueryByExampleExecutor 提供了按实例的查询语法,并允许您根据已知的实体对象创建查询样例。 ExampleMatcher 用于对如何对示例进行匹配进行描述。最后,我们提供了两个示例,演示如何使用 QBE 筛选出需要的实例。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Data JPA系列QueryByExampleExecutor使用详解 - Python技术站