没有为 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()]))
我有一个 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()]))