处理QueryDSL中的可选参数

我在SpringData中使用QueryDSL。 我有Table说, Employee和我创建了实体类说, EmployeeEntity我写了以下服务方法

 public EmployeeEntity getEmployees(String firstName, String lastName) { QEmployeeEntity employee = QEmployeeEntity.employeeEntity; BooleanExpression query = null; if(firstName != null) { query = employee.firstName.eq(firstName); } if(lastName != null) { query = query.and(employee.lastName.eq(lastName)); // NPException if firstName is null as query will be NULL } return empployeeDAO.findAll(query); } 

如上所述,我评论了NPException 。 如何使用Spring数据在QueryDSL中使用QueryDSL作为可选参数?

谢谢 :)

BooleanBuilder可以用作布尔表达式的动态构建器:

 public EmployeeEntity getEmployees(String firstName, String lastName) { QEmployeeEntity employee = QEmployeeEntity.employeeEntity; BooleanBuilder where = new BooleanBuilder(); if (firstName != null) { where.and(employee.firstName.eq(firstName)); } if (lastName != null) { where.and(employee.lastName.eq(lastName)); } return empployeeDAO.findAll(where); } 

BooleanBuilder很好。 你也可以包装它并添加“可选”方法以避免if条件:

例如,对于“和”,您可以编写:(使用Java 8 lambdas)

 public class WhereClauseBuilder implements Predicate, Cloneable { private BooleanBuilder delegate; public WhereClauseBuilder() { this.delegate = new BooleanBuilder(); } public WhereClauseBuilder(Predicate pPredicate) { this.delegate = new BooleanBuilder(pPredicate); } public WhereClauseBuilder and(Predicate right) { return new WhereClauseBuilder(delegate.and(right)); } public  WhereClauseBuilder optionalAnd(@Nullable V pValue, LazyBooleanExpression pBooleanExpression) { return applyIfNotNull(pValue, this::and, pBooleanExpression); } private  WhereClauseBuilder applyIfNotNull(@Nullable V pValue, Function pFunction, LazyBooleanExpression pBooleanExpression) { if (pValue != null) { return new WhereClauseBuilder(pFunction.apply(pBooleanExpression.get())); } return this; } } @FunctionalInterface public interface LazyBooleanExpression { BooleanExpression get(); } 

然后使用会更清洁:

 public EmployeeEntity getEmployees(String firstName, String lastName) { QEmployeeEntity employee = QEmployeeEntity.employeeEntity; return empployeeDAO.findAll ( new WhereClauseBuilder() .optionalAnd(firstName, () -> employee.firstName.eq(firstName)) .optionalAnd(lastName, () -> employee.lastName.eq(lastName)) ); } 

也可以使用jdk的Optional类

实际上这是Java 101:检查null并初始化查询而不是连接谓词。 所以像这样的帮助方法可以做到这一点:

 private BooleanExpression createOrAnd(BooleanExpression left, BooleanExpression right) { return left == null ? right : left.and(right); } 

然后你可以简单地做:

 BooleanExpression query = null; if (firstName != null) { query = createOrAnd(query, employee.firstName.eq(firstName)); } if (lastName != null) { query = createOrAnd(query, employee.lastName.eq(lastName)); } … 

注意,我甚至在第一createOrAnd(…)使用createOrAnd(…)只是为了保持一致性,并且如果您决定在firstName之前添加一个新子句,则不必调整该代码。

根据你的需要,我会这样做

 public List getEmployees(Optional firstName, Optional lastName) { BooleanExpression queryPredicate = QEmployeeEntity.employeeEntity.firstName.containsIgnoreCase(firstName.orElse("")).and(QEmployeeEntity.employeeEntity.lastName.containsIgnoreCase(lastName.orElse(""))); return empployeeDAO.findAll(queryPredicate); } 

首先,您应该返回一份EmployeeEntity List 。 其次,使用可选项比检查它是否为null更好,并且您可以传递从可选的RequestParam获得的Java 8的Optional值,如下所示:

 @RequestMapping(value = "/query", method = RequestMethod.GET) public ModelAndView queryEmployee(@RequestParam(value = "firstName", required = false) Optional firstName, @RequestParam(value = "lastName", required = false) Optional lastName) { List result = getEmployees(firstName, lastName); .... } 

而且一个非常重要的事情是在谓词中使用containsIgnoreCase函数:它比典型的更好,因为它不区分大小写。

在我看来,你应该使用这样的方法:

 @Controller class UserController { @Autowired UserRepository repository; @RequestMapping(value = "/", method = RequestMethod.GET) String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable, @RequestParam MultiValueMap parameters) { model.addAttribute("users", repository.findAll(predicate, pageable)); return "index"; } } 

看看这里 。

如果你检查null的QueryDSL实现:

 public BooleanExpression and(@Nullable Predicate right) { right = (Predicate) ExpressionUtils.extract(right); if (right != null) { return BooleanOperation.create(Ops.AND, mixin, right); } else { return this; } } 

这应该是你想要的。

这是处理可选参数的一种非常简单的方法,我在我的项目中使用它:

  public List findByOptionalsParams(String param1, Integer param2) { QResultEntity qResultEntity = QResultEntity.resultEntity; final JPQLQuery query = from(qResultEntity); if (!StringUtils.isEmpty(param1)) { query.where(qResultEntity.field1.like(Expressions.asString("%").concat(param1).concat("%"))); } if (param2 != null) { query.where(qResultEntity.field2.eq(param2)); } return query.fetch(); } 

我遇到了同样的问题,这里有另一个版本的TimoWestkämper使用Optional的接受答案 。

 default Optional findOne( @Nonnull final String value, @Nullable final String environment, @Nullable final String application, @Nullable final String service) { final QSome Some = QSome.some; final BooleanBuilder builder = new BooleanBuilder(); ofNullable(service).map(some.service::eq).map(builder::and); ofNullable(application).map(some.application::eq).map(builder::and); ofNullable(environment).map(some.environment::eq).map(builder::and); builder.and(some.value.eq(value)); return findOne(builder); }