【问题标题】:JPA Criteria API: Iterate through list and create predicatesJPA Criteria API:遍历列表并创建谓词
【发布时间】:2019-06-22 06:24:52
【问题描述】:


我正在尝试使用 Spring boot、Spring data JPA 和 Hibernate 将 iBatis 项目迁移到 rest 服务。我被困在查询转换中,不胜感激。这是我正在尝试迁移的 iBatis 查询。

<foreach item="item" collection="currentStatus">
    <choose>
        <when test="item in fStatusList">
            ((j_status_code != #{item}) AND (f_status_code = #{item}) AND
            (EXP_FLAG IS NULL OR EXP_FLAG ='F' ))
        </when>
        <when test="item in jStatusList">
            ((max_jsc.status_code = #{item}) AND
                <if test="item ==419">
                    EXP_FLAG='H'
                </if>
                <if test="item ==449">
                    EXP_FLAG='C'
                </if>
            </when>
        <otherwise>
            ((j_status_code = #{item}) AND (f_status_code_name is null))
        </otherwise>
    </choose>
</foreach>

这是我目前所拥有的。

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Job> cq = cb.createQuery(Job.class);
    Root<Job> job = cq.from(Job.class);
    List<Predicate> predicates = new ArrayList<>();
    for (int status : statusList) {
    if (IntStream.of(fStatusList()).anyMatch(x -> x == status)) {
        predicates.add(cb.equal(job.get("f_status_code"), status));
        predicates.add(
            cb.or(
                cb.isNull(job.get("EXP_FLAG")),
                cb.equal(
                    job.get("EXP_FLAG"),"F")));
      } else if (IntStream.of(jStatusList()).anyMatch(x -> x == status)) {
        predicates.add(cb.equal(job.get("jobStatusCode"), status));
        if (status == 10) {
          predicates.add(
              cb.equal(
                  job.get("EXP_FLAG"), "H"));
        } else if (status == 15) {
          predicates.add(
              cb.equal(
                  job.get("EXP_FLAG"), "C"));
        }
      } else {
        predicates.add(
            cb.and(
                cb.isNull(job.get("f_status_code")),
                cb.equal(job.get("j_status_code"), status)));
      }
}
    cq.where(predicates.toArray(new Predicate[0]));
    TypedQuery<Job> query = entityManager.createQuery(cq);

问题是 where 条件正在形成,如下所示。迭代需要为每个状态添加 OR 条件,而不是 AND。我怎样才能做到这一点?

where
 (
 job0_.f_status_code is null
 ) 
 and job0_.j_status_code=315 
 and job0_.j_status_code=449 
 and job0_.exp_flag=?

另外请告知在这些情况下使用 JPA Criteria API 是否是最佳选择。对于一些简单的 iBatis 条件,它似乎相当复杂且难以阅读。使用 Hibernate 时有更好的选择吗?

【问题讨论】:

  • 您正在使用 Spring,因此请查看带有规范模式的 Spring Data JPA 扩展。请参阅此处以获取使用标准 API 的示例和替代方法 - QueryDsl - 我发现它更易于使用:spring.io/blog/2011/04/26/…。另请参阅以下内容,其中指出 JPA Criteria API 有一个主要缺陷:实现复杂查询非常困难,甚至更难阅读。 还讨论了 QueryDsl 作为替代方案:petrikainulainen.net/programming/spring-framework/…
  • 谢谢。我确实查看了规范模式,似乎很难实现像这样的动态查询。将看看 QueryDsl。

标签: java spring hibernate jpa criteria-api


【解决方案1】:

CriteriaQuery#where() 在传递谓词数组时创建一个连词,即在它们之间使用and 运算符。 如果您想使用析取,即or 运算符,只需将它们包装为CriteriaBuilder#or()

cq.where(cb.or(predicates.toArray(new Predicate[] {})));

关于您的第二个问题,请考虑已弃用 Hibernate Criteria 以支持 JPA Criteria API:Deprecated createCriteria method in Hibernate 5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-17
    • 2015-01-14
    • 2023-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    相关资源
    最近更新 更多