Spring Data JPA支持非常丰富的查询方式,本文主要介绍Specification查询。
JPA 2 规范引进了criteria查询API。Spring Data JPA对此提供了支持。如果你想使用这个功能,只需要继承JpaSpecificationExecutor接口。这个接口已经实现了基本的查询方法(findOne,findAll,count等)。
public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {
}
JpaSpecificationExecutor主要用到了Specification,它是一个接口,有一个实现类叫Specifications。这个接口主要定义了下面这个方法,在加上一些not, where, and, or等default或static的逻辑方法
public interface Specification<T> {
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
static <T> Specification<T> not(Specification<T> spec) {
return Specifications.negated(spec);
}
static <T> Specification<T> where(Specification<T> spec) {
return Specifications.where(spec);
}
default Specification<T> and(Specification<T> other) {
return Specifications.composed(this, other, AND);
}
default Specification<T> or(Specification<T> other) {
return Specifications.composed(this, other, OR);
}
}
可以看到它其实是一个函数式接口。最重要的是那个抽象方法toPredicate。按照官方的例子,推荐我们使用static方法来生产Specification对象:
public class UserSpecs {
public static Specification<User> ageEqual(int age) {
return (root, query, builder) -> builder.equal(root.get("age"), age);
}
public static Specification<User> nameLike(String pattern) {
return (r, q, b) -> b.like(r.get("name"), pattern);
}
}
然后我们就可以使用它了。测试用例:
@Test
void couldGetUser_givenAge() {
Optional<User> find = userRepository.findOne(ageEqual(24));
assertThat(find.isPresent()).isTrue();
find.ifPresent(x -> assertThat(x.getName()).isEqualTo("Michael"));
}
@Test
void couldGetUser_givenNamePattern() {
Optional<User> find = userRepository.findOne(nameLike("Mi%").and(ageEqual(24)));
assertThat(find.isPresent()).isTrue();
find.ifPresent(x -> assertThat(x.getName()).isEqualTo("Michael"));
}
你也可以在使用的时候现场造一个:
@Test
void couldGetUser_givenCustomSpecification() {
Optional<User> find = userRepository.findOne(((root, query, criteriaBuilder) ->
criteriaBuilder.and(criteriaBuilder.like(root.get("name"), "Mi%"),
criteriaBuilder.equal(root.get("age"), 24),
criteriaBuilder.isFalse(root.get("locked")))
));
assertThat(find.isPresent()).isTrue();
find.ifPresent(x -> assertThat(x.getName()).isEqualTo("Michael"));
}
root、query、criteriaBuild三个参数的类型都是在javax.persistence.criteria包下,且都是在JPA 2.0规范添加的类和接口。这里分别介绍一下三个重要的参数。
Root接口,主要用于处理实体和字段、实体与实体之间的关系。除了上述例子中的取字段的操作以外,还可以做join操作。
CriteriaQuery接口,主要用于对查询结果的处理,包括groupBy、orderBy、having、distinct等操作。
CriteriaBuilder接口,主要用于各种条件查询、模拟sql函数等。
Specification查询主要用于复杂查询。通过三个参数的组合,可以实现基本上绝大部分sql能实现的复杂查询,且基于Java代码,具有很好的可读性。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://wangchengming.blog.csdn.net/article/details/90639553
内容来源于网络,如有侵权,请联系作者删除!