Criteria API - 具有未知数量比较的OR comperator

时间:2016-12-04 20:24:17

标签: java jpa filter filtering criteria

我试图为我的Java Web应用程序实现某种数据过滤机会。 在我的情况下,用户应该能够过滤客户 - 例如,在12月2日之后出生并且拥有clientSate ACTIVE或INCATIVE的客户。 在我的例子中,ACTIVE和INACTIVE是枚举值。

由于用户可以选择2或3甚至5种不同的状态,我这样做:

for (EnumValue enumValue : constraint.getValues().getEnumValue()) {
    ClientState state = ClientState.valueOf(enumValue.getValue());
    predicate = builder.or(builder.equal(client.get(constraint.getField().getValue()), state));
}

但它没有用。

这是我的完整功能代码:

    public List<Client> getClients(List<FilterConstraint> filters) {
    try {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<?> mainQuery = builder.createQuery(Client.class);
        Root<Client> client = mainQuery.from(Client.class);
        Predicate predicate = builder.conjunction();

        for (FilterConstraint constraint : filters) {
            switch (constraint.getOperator()) {
                case AFTER:
                    predicate = builder.and(builder.greaterThan(client.get(constraint.getField().getValue()), constraint.getValues().getStartDate()));
                    break;
                case BEFORE:
                    predicate = builder.and(builder.greaterThan(client.get(constraint.getField().getValue()), constraint.getValues().getStartDate()));
                    break;
                case BETWEEN:
                    if (constraint.getField().getType() == FieldDataType.DATE) {
                        predicate = builder.and(builder.between(client.get(constraint.getField().getValue()), constraint.getValues().getStartDate(), constraint.getValues().getEndDate()));
                    } else {
                        predicate = builder.and(builder.between(client.get(constraint.getField().getValue()), constraint.getValues().getMinValue(), constraint.getValues().getMaxValue()));
                    }
                    break;
                case EMPTY:
                    predicate = builder.and(builder.isEmpty(client.get(constraint.getField().getValue())));
                    break;
                case EQUALS:
                    if (constraint.getField().getType() == FieldDataType.ENUM) {
                        if (constraint.getValues().getEnumValue().size() > 1) {

                            for (EnumValue enumValue : constraint.getValues().getEnumValue()) {
                                ClientState state = ClientState.valueOf(enumValue.getValue());
                                predicate = builder.or(builder.equal(client.get(constraint.getField().getValue()), state));
                            }
                            break;
                        }
                        ClientState state = ClientState.valueOf(constraint.getValues().getEnumValue().get(0).getValue());
                        predicate = builder.or(builder.equal(client.get(constraint.getField().getValue()), state));
                        break;
                    }
                    predicate = builder.and(builder.equal(client.get(constraint.getField().getValue()), constraint.getValues().getValue()));
                    break;
                case LESS_THAN:
                case MORE_THAN:
                case NOT_EMPTY:
                case ON:
                case STARTS_WITH:
                case TODAY:
            }
        }

        CriteriaQuery<Long> cq = builder.createQuery(Long.class);
        cq.select(builder.count(cq.from(Client.class)));
        em.createQuery(cq);
        cq.where(predicate);
        Long count = em.createQuery(cq).getSingleResult();

        mainQuery.where(predicate);
        //TODO Pagination Result should be returned
        TypedQuery<?> q = em.createQuery(mainQuery);
        List<Client> allClients = (List<Client>) q.getResultList();
        return allClients;
    } catch (Exception e) {
        System.out.println(e.getMessage());
        return null;
    }

}

我搜索了很多,并且无法为OR运算符没有确切值的示例提供资金 - 实际上我发现比较2个值或3个 - 而不是更多。

有人能告诉我如何修复我的代码才能在OR表达式中支持任意数量的值?

2 个答案:

答案 0 :(得分:1)

CriteriaBuilder.or接受谓词数组。因此,只需创建一个“等于枚举值”谓词的数组,并调用该数组的or一次。

或者,您可能需要考虑in <enum values>

答案 1 :(得分:0)

词汇是对的。你可以给它一个这样的数组:

 if (constraint.getValues().getEnumValue().size() > 1) {
      List<Predicate> predicates = new ArrayList<>();
       for (EnumValue enumValue : constraint.getValues().getEnumValue()) {
         ClientState state = ClientState.valueOf(enumValue.getValue());                                    predicates.add(builder.equal(client.get(constraint.getField().getValue()), state));
  }
 predicate = builder.or(predicates.toArray(new Predicate[]{}));
     break;
  }

此代码应该适合您