在构建 Spring 数据 JPA 规范时使用 HAVING 子句时无法插入空值检查

Unable to insert null checks when using HAVING clause while building Spring Data JPA Specifications

我的代码目前正在使用下面的查询,我正在将查询转换为 JPA 规范。

@Query("SELECT DISTINCT h, SUM(m.annualIncome) " +
        "FROM Household h LEFT JOIN h.familyMemberList m " +
        "GROUP BY h.id " +
        "HAVING SUM(m.annualIncome) < 100000 " +
        "AND (:householdSize IS NULL OR COUNT(m) = :householdSize) " +
        "AND (:householdIncome IS NULL OR SUM(m.annualIncome) = :householdIncome)")
List<Household> findGrantEligibleHouseholds(@Param("householdSize") long householdSize, @Param("householdIncome") long householdIncome);

这是我目前所做的工作,但以不干净的方式进行。

public static Specification<Household> grantEligibleHouseholdsSpecification(HouseholdCriteria criteria) {
    return Specification.where(
        (root, query, builder) -> {
            List<Predicate> searchCriteria = new ArrayList<>();
            final Join<Household, FamilyMember> householdFamilyMemberJoin = root.join(Household_.familyMemberList, JoinType.LEFT);
            if(criteria.getHousingType() != null) {
                searchCriteria.add(builder.equal(root.get(Household_.housingType), criteria.getHousingType()));
            }
            query.groupBy(root.get(Household_.id));
            if(criteria.getHouseholdIncome() != null && criteria.getHouseholdSize() != null) {
                query.having(builder.lt(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),100000)
                        ,builder.equal(builder.count(householdFamilyMemberJoin),criteria.getHouseholdSize())
                        ,builder.equal(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),criteria.getHouseholdIncome()));
            }
            else if(criteria.getHouseholdIncome() != null) {
                query.having(builder.lt(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),100000)
                        ,builder.equal(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),criteria.getHouseholdIncome() ));
            }
            else if(criteria.getHouseholdSize() != null) {
                query.having(builder.lt(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),100000)
                        ,builder.equal(builder.count(householdFamilyMemberJoin),criteria.getHouseholdSize()));
            }
            else {
                query.having(builder.lt(builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),100000));
            }
            query.multiselect();
            return builder.and(searchCriteria.toArray(new Predicate[searchCriteria.size()]));
        }
    );
}

我该如何改进这段代码,以便将来它可以接受更多条件而无需像这样进行如此多的空值检查?谢谢!

您可以使用与 searchCriteria 相同的方法 - 将多个谓词收集到列表中:

final List<Predicate> havingPredicates = new ArrayList<>();

// default predicates

havingPredicates.add(builder.lt(
        builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)), 
        100000));

// custom predicates

if (criteria.getHouseholdIncome() != null) {
    havingPredicates.add(builder.equal(
            builder.sum(householdFamilyMemberJoin.get(FamilyMember_.annualIncome)),
            criteria.getHouseholdIncome()));
}

if (criteria.getHouseholdSize() != null) {
    havingPredicates.add(builder.equal(
            builder.count(householdFamilyMemberJoin),
            criteria.getHouseholdSize()));
}

query.having(havingPredicates.toArray(new Predicate[0]));