Spring Data JPA
Spring Data JPA
JPA
规范
规范
JPA 2 引入了一个 criteria API,您可以使用它以编程方式构建查询。 通过编写一个 criteria,您可以为域类定义查询的 where 子句。 退一步讲,这些 criteria 可以被视为由 JPA criteria API 约束描述的实体的谓词。
Spring Data JPA 采用了 Eric Evans 的“Domain Driven Design”一书中的规范概念,遵循相同的语义并提供 API 以使用 JPA criteria API 定义此类规范。 要支持规范,您可以扩展您的存储库接口,使用 JpaSpecificationExecutor 接口,如下所示
public interface CustomerRepository extends CrudRepository
…
}
额外的接口具有允许您以各种方式运行规范的方法。 例如,findAll 方法返回所有符合规范的实体,如以下示例所示
List
Specification 接口定义如下
public interface Specification
Predicate toPredicate(Root
CriteriaBuilder builder);
}
规范可以轻松地用于在实体之上构建一组可扩展的谓词,然后可以将这些谓词与 JpaRepository 组合使用,而无需为每个需要的组合声明查询(方法),如以下示例所示
示例 1. Customer 的规范
public class CustomerSpecs {
public static Specification
return (root, query, builder) -> {
LocalDate date = LocalDate.now().minusYears(2);
return builder.lessThan(root.get(Customer_.createdAt), date);
};
}
public static Specification
return (root, query, builder) -> {
// build query here
};
}
}
Customer_ 类型是使用 JPA Metamodel 生成器生成的元模型类型(有关示例,请参阅 Hibernate 实现的文档)。 因此,表达式 Customer_.createdAt 假定 Customer 具有 Date 类型的 createdAt 属性。 除此之外,我们还在业务需求抽象级别上表达了一些 criteria,并创建了可执行的 Specifications。 因此,客户端可能会按如下方式使用 Specification
示例 2. 使用简单的 Specification
List
为什么不为此类数据访问创建查询? 与普通的查询声明相比,使用单个 Specification 并不能获得很多好处。 当您组合它们以创建新的 Specification 对象时,规范的强大之处才会真正显现出来。 您可以通过我们提供的 Specification 的默认方法来实现这一点,以构建类似于以下的表达式
示例 3. 组合规范
MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List
isLongTermCustomer().or(hasSalesOfMoreThan(amount)));
Specification 提供了一些“粘合代码”默认方法来链接和组合 Specification 实例。 这些方法允许您通过创建新的 Specification 实现并将其与已存在的实现相结合来扩展您的数据访问层。
通过 JPA 2.1,CriteriaBuilder API 引入了 CriteriaDelete。 这通过 JpaSpecificationExecutor 的 delete(Specification) API 提供。
示例 4. 使用 Specification 删除条目。
Specification
userRepository.delete(ageLessThan18);
Specification 构建了一个 criteria,其中 age 字段(转换为整数)小于 18。 传递给 userRepository 后,它将使用 JPA 的 CriteriaDelete 功能来生成正确的 DELETE 操作。 然后它返回已删除的实体数。