当前位置: 首页 > 工具软件 > jpa-spec > 使用案例 >

Spring Data JPA - Specifications

卓云
2023-12-01

JPA 2引入了一个标准API,您可以使用它以编程方式构建查询。通过编写条件,可以定义domain class查询的where子句。再后退一步,这些标准可以看作是JPA标准API约束所描述的实体的断言。

Spring Data JPA从Eric Evans的《领域驱动设计》一书中获得了规范的概念,遵循相同的语义,并提供了一个API来用JPA标准API定义这样的规范。为了支持规范,您可以使用JpaSpecificationExecutor接口扩展您的存储库接口,如下所示:

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

附加的接口具有允许您以各种方式运行规范的方法:

public interface JpaSpecificationExecutor<T> {
    Optional<T> findOne(@Nullable Specification<T> var1);

    List<T> findAll(@Nullable Specification<T> var1);

    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

    List<T> findAll(@Nullable Specification<T> var1, Sort var2);

    long count(@Nullable Specification<T> var1);
}
public interface Specification<T> extends Serializable {
    long serialVersionUID = 1L;

    static <T> Specification<T> not(@Nullable Specification<T> spec) {
        return spec == null ? (root, query, builder) -> {
            return null;
        } : (root, query, builder) -> {
            return builder.not(spec.toPredicate(root, query, builder));
        };
    }

    static <T> Specification<T> where(@Nullable Specification<T> spec) {
        return spec == null ? (root, query, builder) -> {
            return null;
        } : spec;
    }

    default Specification<T> and(@Nullable Specification<T> other) {
        return SpecificationComposition.composed(this, other, CriteriaBuilder::and);
    }

    default Specification<T> or(@Nullable Specification<T> other) {
        return SpecificationComposition.composed(this, other, CriteriaBuilder::or);
    }

    @Nullable
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}

规范可以很容易地用于在实体之上构建可扩展的断言,然后可以与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
    };
  }
}

使用简单的规范:

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

 类似资料: