【问题标题】:Returning a QueryDSL BooleanExpression that evaluates to true返回计算结果为 true 的 QueryDSL BooleanExpression
【发布时间】:2012-08-30 09:22:20
【问题描述】:

假设我有具有以下属性的 CustomerQueryInfo bean:

  • 字符串名字
  • 字符串姓氏
  • StatusEnum 状态

我想使用此类型的对象执行“QueryDSL”搜索,该对象将返回客户列表List<Customer>

如果CustomerQueryInfo 的字段之一是null,我不想在搜索中使用它。因此,所有三个字段都设置为nullCustomerQueryInfo 对象将返回所有客户

我正在寻找使用 QueryDSL 执行此类搜索的最佳做法。

这样可以吗:

private BooleanExpression isFirstNameLike(String firstName){
    if(firstName==null)
        return true BooleanExpression somehow;
    return QCustomer.customer.firstName.like(firstName);
}

private BooleanExpression isStatutEq(StatusEnum status){
    if(status==null)
        return true BooleanExpression somehow;
    return QCustomer.customer.status.eq(status);
}

然后:

return query.from(customer).where(isFirstNameLike(customerQueryInfo.getFirstName).and(isLastNameLike(customerQueryInfo.getLastName).and(isStatusEq(customerQueryInfo.getStatus))).list;
  1. 如何返回评估结果为 true 的 BooleanExpression
  2. 如果上述方法不可取,那么推荐的最佳做法是什么?

【问题讨论】:

    标签: java null querydsl


    【解决方案1】:

    如何返回计算结果为 true 的 BooleanExpression?

    BooleanExpression alwaysTrue = Expressions.asBoolean(true).isTrue();
    

    【讨论】:

    • 似乎是一个很好的解决方案,但就我而言,我最终得到了java.lang.UnsupportedOperationException: Illegal operation true = true at com.querydsl.mongodb.MongodbSerializer.visit(MongodbSerializer.java:259
    • 在这里与 Oracle 合作。似乎是与MongoDB结合的问题。
    • 实际上,BooleanBuilder(请参阅 Lam Le 的回答)最终完美运行。一开始我并没有意识到BooleanBuilderPredicate,所以一旦你完成构建,你可以将它直接传递给where 子句。
    • @FabianBarney Expressions.TRUE.isTrue() 确实如此
    • @FabianBarney 会稍微快一些,跳过大约 6 个方法调用。
    【解决方案2】:

    您可以安全地使用这样的空谓词

    private BooleanExpression isFirstNameLike(String firstName){
        return firstName != null ? customer.firstName.like(firstName) : null;        
    }
    
    private BooleanExpression isStatusEq(StatusEnum status){
        return status != null ? customer.status.eq(status) : null;
    }
    

    并使用 where 的可变参数方面

    query.from(customer)
         .where(
             isFirstNameLike(customerQueryInfo.getFirstName()),
             isLastNameLike(customerQueryInfo.getLastName()),
             isStatusEq(customerQueryInfo.getStatus()))
         .list(customer);
    

    【讨论】:

    • 不确定是否相关,但今天我在 QueryDSL 3.5.0(使用 spring-data-jpa)中遇到了一个问题,isTrue() 正确返回了所有内容,但 eq(Boolean.TRUE) 没有返回任何内容。但是,eq(Boolean.FALSE) 工作正常。这是一个错误吗?
    • 在记录的地方跳过空值。是否可以对BooleanExpression.and(Predicate) 做同样的事情?目前,null 跳过是这里的一个实现细节,当参数注释为 @Nullable 时,没有记录 null 行为。
    【解决方案3】:

    使用 java 8 和 BooleanBuilder 你可以像这样优雅地实现:

    Java 8 可选和 Lambda

    public final class ProductQuery {
        public static BooleanExpression nameEqualTo(String name){
            return ofNullable(name).map(QProduct.product.name::eq).orElse(null);
        }
    }
    

    BooleanBuilder

    BooleanBuilder where = new BooleanBuilder()
        .and(ProductQuery.nameEqualTo(name));
    

    【讨论】:

      【解决方案4】:

      我创建了一个 QueryDSLHelper 类,该类具有在添加表达式之前执行 null 检查的静态方法。像这样的:

      public static void goe(BooleanBuilder builder, DateTimePath<Date> path, Date value) {
          if(date!=null) {
              builder.and(path.goe(value));
          }
      }
      
      public static void like(BooleanBuilder builder, StringPath path, String value) {
          if(value!=null) {
              builder.and(path.like(value));
          }
      }
      

      现在我可以静态导入这些方法并在一行中调用它们:

              like(builder, book.isbn, isbn);
      

      这在实现“filter”或“filterByExample”查询时非常有用且非常简洁/易读。

      虽然,蒂莫的上述答案可能是更好的解决方案。

      【讨论】:

        【解决方案5】:

        你可以这样做:

        private BooleanExpression isFirstNameLike(String firstName){
            final QCustomer customer = QCustomer.customer;
            return customer.firstName.isNull().or(customer.firstName.like(firstName));
        }
        
        private BooleanExpression isStatutEq(StatusEnum status){
            final QCustomer customer = QCustomer.customer;
            return customer.status.isNull().or(customer.status.eq(status));    
        }
        

        或者如果你想真正匹配firstName 和/或状态然后改变

        .isNull().or(...) to isNotNull().and(...)
        

        【讨论】:

          猜你喜欢
          • 2021-09-21
          • 1970-01-01
          • 1970-01-01
          • 2020-12-10
          • 1970-01-01
          • 1970-01-01
          • 2013-05-26
          • 2013-05-15
          • 1970-01-01
          相关资源
          最近更新 更多