没有为 Spring JPA 条件指定值时如何避免 NPE

How to avoid NPE when no values is specified for Spring JPA criteria

我有一个 Spring JPA 搜索条件,如下所示。其中 area 是一个整数。

cb.between(root.get(Property_.area), searchConstraint.getAreaMin(), searchConstraint.getAreaMax())

问题是,当用户在搜索中没有指定上限或下限时,该值为空,这会导致NPE。我想到的一件事是对 null 值进行 if 检查并将该值设置为 Integer.MAX_VAL 如果它是 null 作为一种工作 around.This 我可以避免 NPE 的方法,但它也会创建很多 if else 检查。所以想知道有没有更好的方法。

我想到了两个更清洁的解决方案:

  • 使用选项,例如`Optional.ofNullable(searchConstraint.getAreaMax()).orElse(Integer.MAX_VALUE)
  • areaMin 和 areaMax 应该有合理的默认值,只有在用户提供一些数据时才会被覆盖;数据本身应该被验证

如果 getAreaMin 和 getAreaMax 为 NULL,您可以 avoid/ignore 添加此条件。 如果 getAreaMin 为 NULL 且 getAreaMax 为 NOT NULL,则可以使用 le() 而不是 between ,对于 getAreaMax 和 gt() 方法也是如此; 'if'代码没问题

像这样:

 if(isNotNull(searchConstraint.getAreaMin()) && isNotNull(searchConstraint.getAreaMax())) {
         cb.between(root.get(Property_.area), searchConstraint.getAreaMin(), searchConstraint.getAreaMax())
 }else{
     if(isNotNull(searchConstraint.getAreaMin()){
          cb.gt(root.get(Property_.area), searchConstraint.getAreaMin());
     }else{
          cb.le(root.get(Property_.area), searchConstraint.getAreaMax());
     }
 } 

或者您可以创建一个 util 方法,例如(但 prev 变体更好地解决性能问题):

private Integer getValueOrDefault(Integer value , Integer defaultValue){
    return value==null ? defaultValue : value;
}

执行: cb.between(root.get(Property_.area), getValueOrDefault(searchConstraint.getAreaMin(), Integer.MIN_VALUE), getValueOrDefault(searchConstraint.getAreaMax(), Integer.MAX_VALUE))

如果两个值都可以为空,我建议将 between 查询拆分为两个谓词,然后将它们合并。这样你也可以处理 both of them are null:

List<Predicate> predicates = new ArrayList<>();
if (searchConstraint.getAreaMin() != null)
    predicates.add(cb.gt(root.get(Property_.area), searchConstraint.getAreaMin()))
if (searchConstraint.getAreaMax() != null)
    predicates.add(cb.lt(root.get(Property_.area), searchConstraint.getAreaMax()))
if (predicates.size() > 0)
    cb.and(predicates.toArray(new Predicate[predicates.size()]))