跳到主要内容

规格说明

DeepSeek V3 中英对照 Specifications

JPA 2 引入了一种 Criteria API,你可以使用它以编程方式构建查询。通过编写 criteria,你定义了针对某个领域类的查询的 where 子句。进一步来说,这些 criteria 可以视为由 JPA Criteria API 约束所描述的实体上的谓词。

Spring Data JPA 从 Eric Evans 的书籍《领域驱动设计》中引入了规范的概念,遵循相同的语义,并提供了使用 JPA 条件 API 定义此类规范的 API。为了支持规范,你可以通过扩展 JpaSpecificationExecutor 接口来扩展你的仓库接口,如下所示:

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {

}
java

附加接口提供了多种方法来运行规范(specifications)。例如,findAll 方法会返回所有符合规范的实体,如下例所示:

List<T> findAll(Specification<T> spec);
java

Specification 接口定义如下:

public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
java

规范可以很容易地用于在实体之上构建一组可扩展的谓词,然后这些谓词可以组合并与 JpaRepository 一起使用,而无需为每个需要的组合声明查询(方法),如下例所示:

示例 1. 客户的规格说明

public class CustomerSpecs {

public static Specification<Customer> isLongTermCustomer() {
return (root, query, builder) -> {
LocalDate date = LocalDate.now().minusYears(2);
return builder.lessThan(root.get(Customer_.createdAt), date);
};
}

public static Specification<Customer> hasSalesOfMoreThan(MonetaryAmount value) {
return (root, query, builder) -> {
// build query here
};
}
}
java

Customer_ 类型是使用 JPA 元模型生成器生成的元模型类型(参见 Hibernate 实现的文档以获取示例)。因此,表达式 Customer_.createdAt 假设 Customer 有一个类型为 DatecreatedAt 属性。除此之外,我们还在业务需求抽象层面上表达了一些标准,并创建了可执行的 Specifications。因此,客户端可以如下使用 Specification

示例 2. 使用一个简单的规范

List<Customer> customers = customerRepository.findAll(isLongTermCustomer());
java

为什么不为此类数据访问创建一个查询呢?使用单一的 Specification 相比普通的查询声明并没有带来太多好处。当你组合它们以创建新的 Specification 对象时,Specification 的强大之处才能真正体现出来。你可以通过我们提供的 Specification 的默认方法来构建类似于以下表达式的组合:

示例 3. 组合规范

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
isLongTermCustomer().or(hasSalesOfMoreThan(amount)));
java

Specification 提供了一些“粘合代码”默认方法,用于链式和组合 Specification 实例。这些方法允许你通过创建新的 Specification 实现并将其与已有的实现组合在一起来扩展你的数据访问层。

在 JPA 2.1 中,CriteriaBuilder API 引入了 CriteriaDelete。这是通过 JpaSpecificationExecutordelete(Specification) API 提供的。

示例 4. 使用 Specification 删除条目。

Specification<User> ageLessThan18 = (root, query, cb) -> cb.lessThan(root.get("age").as(Integer.class), 18)

userRepository.delete(ageLessThan18);
java

Specification 构建了一个条件,其中 age 字段(转换为整数)小于 18。将其传递给 userRepository 后,它将使用 JPA 的 CriteriaDelete 特性来生成正确的 DELETE 操作。然后返回被删除的实体数量。