为了账号安全,请及时绑定邮箱和手机立即绑定

具有任意AND子句的动态spring数据jpa存储库查询

/ 猿问

具有任意AND子句的动态spring数据jpa存储库查询

犯罪嫌疑人X 2019-08-13 10:13:39

具有任意AND子句的动态spring数据jpa存储库查询

我正在使用Spring data jpa repositories,要求提供不同字段的搜索功能。搜索之前输入的字段是optional.I有5场说EmployeeNumberNameMarriedProfessionDateOfBirth
这里我只需要用户查询给定的值,其他字段应该被忽略.Ex,

Input : EmployeeNumber: ,Name:St,Married: ,Professsion:IT,DateOfBirth: Query : Select * from Employee e where Name like 'St%' and Profession like 'IT%';  Input : EmployeeNumber:10,Name: ,Married: ,Professsion:IT,DateOfBirth:Query : Select * from Employee e where EmployeeNumber like '10%' and Profession like 'IT%';

所以我们在这里考虑输入和查询的值。在这种情况下,春季数据是具有限制中提到的这篇文章不可扩展,所有可能出现的问题,应书面)我使用的Querydsl,但仍存在问题,null待开发领域应该被忽略,几乎所有可能的查询需要。在这case 31 queries。如果搜索字段是6,7,8...??

使用可选字段实现搜索选项的最佳方法是什么?


查看完整描述

3 回答

?
慕田峪7331174

请注意,使用新的主要版本的QueryDSL(4.x)和querydsl-jpa可能会有更改


在我们的一个项目中,我们使用QueryDSLQueryDslPredicateExecutor<T>

  public Predicate createPredicate(DataEntity dataEntity) {
    QDataEntity qDataEntity = QDataEntity.dataEntity;
    BooleanBuilder booleanBuilder = new BooleanBuilder();
    if (!StringUtils.isEmpty(dataEntity.getCnsiConsumerNo())) {
      booleanBuilder        .or(qDataEntity.cnsiConsumerNo.contains(dataEntity.getCnsiConsumerNo()));
    }
    if (!StringUtils.isEmpty(dataEntity.getCnsiMeterNo())) {
      booleanBuilder.or(qDataEntity.cnsiMeterNo.contains(dataEntity.getCnsiMeterNo()));
    }

    return booleanBuilder.getValue();
  }

我们可以在存储库中使用它:

@Repositorypublic interface DataEntityRepository
  extends DaoRepository<DataEntity, Long> {

哪里DaoRepository

@NoRepositoryBeanpublic interface DaoRepository<T, K extends Serializable>
  extends JpaRepository<T, K>,
  QueryDslPredicateExecutor<T> {}

因此,您可以使用存储库谓词方法。

Iterable<DataEntity> results = dataEntityRepository.findAll(dataEntityPredicateCreator.createPredicate(dataEntity));

要获取QClasses,您需要在pom.xml中指定QueryDSL APT Maven插件

  <build>
    <plugins>
      <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>maven-apt-plugin</artifactId>
        <version>1.0.4</version>
        <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <outputDirectory>target/generated-sources</outputDirectory>
              <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
          </execution>
        </executions>
      </plugin>

依赖性是

    <!-- querydsl -->
    <dependency>
        <groupId>com.mysema.querydsl</groupId>
        <artifactId>querydsl-core</artifactId>
        <version>${querydsl.version}</version>
    </dependency>
    <dependency>
        <groupId>com.mysema.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
    </dependency>
    <dependency>
        <groupId>com.mysema.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <version>${querydsl.version}</version>
    </dependency>

或者对于Gradle:

sourceSets {
    generated}sourceSets.generated.java.srcDirs = ['src/main/generated']configurations {
    querydslapt}dependencies {
    // other deps ....
    compile "com.mysema.querydsl:querydsl-jpa:3.6.3"
    compile "com.mysema.querydsl:querydsl-apt:3.6.3:jpa"}task generateQueryDSL(type: JavaCompile, group: 'build', description: 'Generates the QueryDSL query types') {
    source = sourceSets.main.java
    classpath = configurations.compile + configurations.querydslapt
    options.compilerArgs = [
            "-proc:only",
            "-processor", "com.mysema.query.apt.jpa.JPAAnnotationProcessor"
    ]
    destinationDir = sourceSets.generated.java.srcDirs.iterator().next()}compileJava {
    dependsOn generateQueryDSL
    source generateQueryDSL.destinationDir}compileGeneratedJava {
    dependsOn generateQueryDSL
    classpath += sourceSets.main.runtimeClasspath}


查看完整回答
反对 回复 2019-08-13
?
繁华开满天机

您可以使用Spring-data为您提供开箱即用的规格。并且能够使用条件API以编程方式构建查询。要支持规范,您可以使用JpaSpecificationExecutor接口扩展存储库接口

public interface CustomerRepository extends SimpleJpaRepository<T, ID>, JpaSpecificationExecutor {}

附加接口(JpaSpecificationExecutor)包含允许您以各种方式执行规范的方法。

例如,findAll方法将返回与规范匹配的所有实体:

List<T> findAll(Specification<T> spec);

规范界面如下:

public interface Specification<T> {
     Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
            CriteriaBuilder builder);}

好的,那么典型的用例是什么?可以轻松地使用规范在实体之上构建可扩展的谓词集,然后可以将其与JpaRepository结合使用,而无需为每个所需组合声明查询(方法)。这是一个例子:例2.15。客户规格

public class CustomerSpecs {
    public static Specification<Customer> isLongTermCustomer() {
        return new Specification<Customer>() {
            public Predicate toPredicate(
                Root<Customer> root, CriteriaQuery<?> query,
                CriteriaBuilder builder) {
                LocalDate date = new LocalDate().minusYears(2);
                return builder.lessThan(root.get('dateField'), date);
            }
        };
    }

    public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
        return new Specification<Customer>() {
            public Predicate toPredicate(
                Root<T> root, CriteriaQuery<?> query,
                CriteriaBuilder builder) {
                // build query here
            }
        };
    }}

您在业务需求抽象级别上表达了一些标准并创建了可执行规范。所以客户端可能会使用如下规范:

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

您还可以组合规范示例2.17。组合规格

    MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
    List<Customer> customers = customerRepository.findAll(
        where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));

如您所见,规格提供了一些胶水代码方法来链接和组合规格。因此,扩展数据访问层只需要创建新的规范实现并将它们与已存在的实现相结合。

您可以创建复杂规范,这是一个示例

public class WorkInProgressSpecification {
    public static Specification<WorkInProgress> findByCriteria(final SearchCriteria searchCriteria) {

        return new Specification<WorkInProgress>() {

            @Override
            public Predicate toPredicate(
                Root<WorkInProgress> root,
                CriteriaQuery<?> query, CriteriaBuilder cb) {

                List<Predicate> predicates = new ArrayList<Predicate>();

                if (searchCriteria.getView() != null && !searchCriteria.getView().isEmpty()) {
                    predicates.add(cb.equal(root.get("viewType"), searchCriteria.getView()));
                }
                if (searchCriteria.getFeature() != null && !searchCriteria.getFeature().isEmpty()) {
                    predicates.add(cb.equal(root.get("title"), searchCriteria.getFeature()));
                }
                if (searchCriteria.getEpic() != null && !searchCriteria.getEpic().isEmpty()) {
                    predicates.add(cb.equal(root.get("epic"), searchCriteria.getEpic()));
                }
                if (searchCriteria.getPerformingGroup() != null && !searchCriteria.getPerformingGroup().isEmpty()) {
                    predicates.add(cb.equal(root.get("performingGroup"), searchCriteria.getPerformingGroup()));
                }
                if (searchCriteria.getPlannedStartDate() != null) {
                    System.out.println("searchCriteria.getPlannedStartDate():" + searchCriteria.getPlannedStartDate());
                    predicates.add(cb.greaterThanOrEqualTo(root.<Date>get("plndStartDate"), searchCriteria.getPlannedStartDate()));
                }
                if (searchCriteria.getPlannedCompletionDate() != null) {
                    predicates.add(cb.lessThanOrEqualTo(root.<Date>get("plndComplDate"), searchCriteria.getPlannedCompletionDate()));
                }
                if (searchCriteria.getTeam() != null && !searchCriteria.getTeam().isEmpty()) {
                    predicates.add(cb.equal(root.get("agileTeam"), searchCriteria.getTeam()));
                }

                return cb.and(predicates.toArray(new Predicate[] {}));
            }
        };
    }}

这是JPA Respositories文档


查看完整回答
反对 回复 2019-08-13
?
精慕HU

从Spring Data JPA 1.10开始,还有一个选项是Query By Example。您的存储库应该JpaRepositoryQueryByExampleExecutor接口分开实现,您可以在其中获取以下方法:

<S extends T> Iterable<S> findAll(Example<S> example)

然后创建示例以搜索like:

Employee e = new Employee();e.setEmployeeNumber(getEmployeeNumberSomewherFrom());e.setName(getNameSomewhereFrom());e.setMarried(getMarriedSomewhereFrom());e.setProfession(getProfessionSomewhereFrom());e.setDateOfBirth(getDateOfBirthSomewhereFrom());

然后:

employeeRepository.findAll(Example.of(e));

如果某些参数为null,则不会将其引入WHERE子句,因此您将获得动态查询。

为了完善匹配的字符串属性来看看ExampleMatcher

例如ExampleMatcher,不区分大小写的like是:

ExampleMatcher matcher = ExampleMatcher.matching().
          withMatcher("profession", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.CONTAINING).ignoreCase());

QBE示例:https//github.com/spring-projects/spring-data-examples/tree/master/jpa/query-by-example


查看完整回答
反对 回复 2019-08-13

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信