Spring Data JPA

JPA

规范

规范

JPA 2 引入了条件 API,您可以使用它以编程方式构建查询。通过编写 criteria,您可以定义域类的查询的 where 子句。退一步讲,这些条件可以被视为通过 JPA 条件 API 约束描述的实体上的谓词。

Spring Data JPA 借鉴了 Eric Evans 的著作《领域驱动设计》中“规范”的概念,遵循相同的语义并提供了一个 API 来使用 JPA 条件 API 定义此类规范。为了支持规范,您可以通过 JpaSpecificationExecutor 接口扩展您的存储库接口,如下所示

public interface CustomerRepository extends CrudRepository, JpaSpecificationExecutor {

}

附加接口具有允许您以多种方式运行规范的方法。例如,findAll 方法返回所有与规范匹配的实体,如以下示例所示

List findAll(Specification spec);

Specification 接口定义如下

public interface Specification {

Predicate toPredicate(Root root, CriteriaQuery query,

CriteriaBuilder builder);

}

规范可以轻松地用于在实体之上构建一组可扩展的谓词,然后可以与 JpaRepository 结合使用,而无需为每个所需的组合声明查询(方法),如以下示例所示

示例 1. 客户规范

public class CustomerSpecs {

public static Specification isLongTermCustomer() {

return (root, query, builder) -> {

LocalDate date = LocalDate.now().minusYears(2);

return builder.lessThan(root.get(Customer_.createdAt), date);

};

}

public static Specification hasSalesOfMoreThan(MonetaryAmount value) {

return (root, query, builder) -> {

// build query here

};

}

}

Customer_ 类型是使用 JPA 元模型生成器生成的元模型类型(请参阅 Hibernate 实现文档中的示例)。因此,表达式 Customer_.createdAt 假定 Customer 具有类型为 Date 的 createdAt 属性。除此之外,我们还在业务需求抽象级别上表达了一些条件,并创建了可执行的 Specifications。因此,客户端可以使用 Specification,如下所示

示例 2. 使用简单的规范

List customers = customerRepository.findAll(isLongTermCustomer());

为什么不为这种类型的数据访问创建查询?使用单个 Specification 相对于普通的查询声明并没有带来太多好处。规范的强大之处在于当您将它们组合起来创建新的 Specification 对象时。您可以通过我们提供的 Specification 的默认方法来实现这一点,以构建类似于以下内容的表达式

示例 3. 组合规范

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);

List customers = customerRepository.findAll(

isLongTermCustomer().or(hasSalesOfMoreThan(amount)));

Specification 提供了一些“粘合代码”默认方法来链接和组合 Specification 实例。这些方法允许您通过创建新的 Specification 实现并将它们与现有实现结合来扩展您的数据访问层。

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

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

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

userRepository.delete(ageLessThan18);

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