从 Criteria 获取 WHERE 子句作为 HQL 字符串或:select 中具有动态列的动态 WHERE 子句

Get WHERE clause as HQL string from Criteria or: Dynamic WHERE clause with dynamic columns in select

我想为我的应用程序构建过滤器搜索。但是,有一些限制。我必须能够动态添加条件以及动态修改我想要获取的列和连接。

我尝试使用带有规范的 JPA 存储库(来自 Spring 数据),它根据需要构建 WHERE 子句,但是我无法控制哪些列以及将 Hibernate 问题连接到数据库的内容。

我也尝试过将 Hibernate Criteria API 与投影一起使用。发出的 Query 符合要求,我完全控制了选定的列和连接,以及 WHERE 子句,但是结果转换被证明对于解析嵌套对象来说太麻烦了(我尝试使用自定义结果转换器,但是无济于事,对于单层对象,默认行为很好。

我现在的 "solution" 正在根据情况构建 HQL 字符串。但是,我已经编写了用于构建 WHERE 子句的代码,我想知道是否有重用它的方法(例如,从 Spring 规范的谓词或从 Hibernate 限制中获取 HQL 字符串)。

当然,如果有更好的方法,请分享。

您需要使用 QueryDSL.

第 1 步:com.mysema.querydsl:querydsl-aptcom.mysema.querydsl:querydsl-corecom.mysema.querydsl:querydsl-jpa 依赖项添加到您的项目。

第 2 步:向实体 class 添加 @QueryEntity 注释,您希望对其进行 运行 动态查询。如果查询将包含嵌套 classes,请将注释添加到嵌套实体 classes 中。下面的例子:

@Entity
@QueryEntity
@Table(name = "users")
public class User {
  @OneToMany
  private Address address;
}

@Entity
@QueryEntity
@Table(name = "address")
public class Address {
  @ManyToOne
  private Country country;
}

@Entity
@QueryEntity
@Table(name = "country")
public class Country { }

步骤3:运行com.mysema.maven:apt-maven-pluginMaven插件在process阶段如下:

<build>
  <plugins>
    <plugin>
      <groupId>com.mysema.maven</groupId>
      <artifactId>apt-maven-plugin</artifactId>
      <version>1.1.1</version>
      <executions>
        <execution>
          <goals>
            <goal>process</goal>
          </goals>
          <configuration>
            <outputDirectory>target/generated-sources/java</outputDirectory>
            <processor>com.mysema.query.apt.QuerydslAnnotationProcessor</processor>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

步骤 4:更改 Spring 数据 JPA 存储库接口以扩展 QueryDslPredicateExecutor

interface UserRepository extends JpaRepository<User, Long>, QueryDslPredicateExecutor<User> {}

通过此设置,APT 插件将为每个用 QueryEntity 注释的 class 生成 Q classes。然后,您可以使用这些 classes 生成动态查询。例如:

QUser user = QUser.user;

BooleanExpression query = and(eq(user.active, Boolean.TRUE), eq(user.address.country.name, "Belgium"));

Collection<User> activeUsersFromBelgium = userRepository.findAll(query);