【问题标题】:Criteria API - OR comperator with unknown number of comparisonsCriteria API - 具有未知比较次数的 OR 比较器
【发布时间】:2017-04-19 04:41:41
【问题描述】:

我正在尝试为我的 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 表达式中的任意数量的值?

【问题讨论】:

    标签: java jpa filter filtering criteria


    【解决方案1】:

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

    或者,您也可以考虑使用in &lt;enum values&gt;

    【讨论】:

    • ArrayList 谓词 = new ArrayList(); for (EnumValue enumValue : constraint.getValues().getEnumValue()) { ClientState state = ClientState.valueOf(enumValue.getValue());谓词.add(builder.equal(client.get(constraint.getField().getValue()), state)); } 谓词 = builder.or(谓词); - 它告诉我:没有输入。我做错了什么?你能给我代码示例吗?
    • @Irakli 看,这足以作为提示。我礼貌地拒绝为您编写代码。
    【解决方案2】:

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

     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;
      }
    

    这段代码应该适合你

    【讨论】:

    • 在这种情况下,只评估 Or 表达式,而忽略其他谓词。我需要将它们都包括在内。
    猜你喜欢
    • 1970-01-01
    • 2012-07-01
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2021-09-06
    • 2012-03-15
    • 2016-03-24
    相关资源
    最近更新 更多