JPA 2 引入了一个条件 API,您可以使用它以编程方式构建查询。通过编写 ,可以定义域类查询的 where 子句。再往后退一步,这些条件可以看作是 JPA 标准 API 约束所描述的实体的谓词。criteria
Spring Data JPA 采用了 Eric Evans 的《领域驱动设计》一书中的规范概念,遵循相同的语义,并提供了一个 API 来使用 JPA 标准 API 定义此类规范。为了支持规范,您可以使用该接口扩展存储库接口,如下所示:JpaSpecificationExecutor
public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
…
}
附加界面具有允许您以多种方式运行规范的方法。例如,该方法返回与规范匹配的所有实体,如以下示例所示:findAll
List<T> findAll(Specification<T> spec);
接口定义如下:Specification
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
规范可以很容易地用于在实体之上构建一组可扩展的谓词,然后可以组合和使用这些谓词,而无需为每个需要的组合声明查询(方法),如以下示例所示:JpaRepository
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
};
}
}
该类型是使用 JPA 元模型生成器生成的元模型类型(有关示例,请参阅 Hibernate 实现的文档)。
因此,表达式 假定 具有 类型的属性。
除此之外,我们还在业务需求抽象级别上表达了一些标准并创建了可执行文件。
因此,客户端可以使用如下所示:Customer_
Customer_.createdAt
Customer
createdAt
Date
Specifications
Specification
List<Customer> customers = customerRepository.findAll(isLongTermCustomer());
为什么不为这种数据访问创建查询呢?与普通查询声明相比,使用单个查询不会获得很多好处。当您将规范组合在一起以创建新对象时,它们的力量确实会大放异彩。您可以通过我们提供的默认方法来构建类似于以下内容的表达式来实现这一点:Specification
Specification
Specification
MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
isLongTermCustomer().or(hasSalesOfMoreThan(amount)));
Specification
提供一些“胶水代码”默认方法来链接和组合实例。通过这些方法,您可以通过创建新实现并将其与现有实现相结合来扩展数据访问层。Specification
Specification
在 JPA 2.1 中,引入了 API。这是通过 API 提供的。CriteriaBuilder
CriteriaDelete
JpaSpecificationExecutor’s `delete(Specification)
Specification
Specification<User> ageLessThan18 = (root, query, cb) -> cb.lessThan(root.get("age").as(Integer.class), 18)
userRepository.delete(ageLessThan18);
构建一个条件,其中字段(转换为整数)小于 。
传递给 ,它将使用 JPA 的功能来生成正确的操作。
然后,它返回已删除的实体数。Specification
age
18
userRepository
CriteriaDelete
DELETE