Действительно динамический JPA CriteriaBuilder

Мне нужно создать "настоящий" динамический JPA CriteriaBuilder. Я получаю Mapс операторами. Это выглядит так:

name : John
surname : Smith
email : email@email.de

...more pairs possible

Вот что я реализую:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> userRoot = query.from(User.class);
query.select(userRoot);

List<Predicate> predicates = new ArrayList<Predicate>();
Iterator<String> column = statements.keySet().iterator();
while (column.hasNext()) {

    // get the pairs
    String colIndex = column.next();
    String colValue = statements.get(colIndex);

    // create the statement
    Predicate pAnd = cb.conjunction();
    pAnd = cb.and(pAnd, cb.equal(userRoot.get(colIndex), colValue));
    predicates.add(pAnd);
}

// doesn't work, i don't know how many predicates i have -> can not address them
query.where(predicates.get(0), predicates.get(1), ...);

// doesn't work, because it is a list of predicates
query.where(predicates);

// doesn't work, because the actual predicate overwrites the old predicate
for (Predicate pre : predicates) {
     query.where(pre)
}

Я попытался создать большой Predicate, который содержит все остальные предикаты, и добавить его в query.where(), но снова предикаты перезаписывают старые значения. Похоже, нет возможности добавить Predicateвместо изменения Predicate :-(

Реальный проект еще сложнее, потому что некоторые пары требуют equal, а некоторые другие a like, И этого даже недостаточно: может быть дополнительный оператор с или , включенный как type : 1;4;7, Здесь значение должно разделите и создайте оператор, например:

<остальная часть оператора> И (тип = 1 ИЛИ тип = 4 ИЛИ тип = 7)

ОБНОВЛЕНИЕ и РЕШЕНИЕ Получил два списка, первый список для AND работает хорошо. Второй список содержит операторы ИЛИ, такие как exspected:

final List<Predicate> andPredicates = new ArrayList<Predicate>();
final List<Predicate> orPredicates = new ArrayList<Predicate>();
for (final Entry<String, String> entry : statements.entrySet()) {
    final String colIndex = entry.getKey();
    final String colValue = entry.getValue();
    if (colIndex != null && colValue != null) {

        if (!colValue.contains(";")) {
            if (equals) {
                andPredicates.add(cb.equal(userRoot.get(colIndex), colValue));
            } else {
                andPredicates.add(cb.like(userRoot.<String> get(colIndex), "%" + colValue + "%"));
            }
        } else {
            String[] values = colValue.split(";");
            for (String value : values) {
                orPredicates.add(cb.or(cb.equal(userRoot.get(colIndex), value)));
            }
        }       
    }
}

// Here goes the magic to combine both lists
if (andPredicates.size() > 0 && orPredicates.size() == 0) {
    // no need to make new predicate, it is already a conjunction
    query.where(andPredicates.toArray(new Predicate[andPredicates.size()]));
} else if (andPredicates.size() == 0 && orPredicates.size() > 0) {
    // make a disjunction, this part is missing above
    Predicate p = cb.disjunction();
    p = cb.or(orPredicates.toArray(new Predicate[orPredicates.size()]));
    query.where(p);
} else {
    // both types of statements combined
    Predicate o = cb.and(andPredicates.toArray(new Predicate[andPredicates.size()]));
    Predicate p = cb.or(orPredicates.toArray(new Predicate[orPredicates.size()]));
    query.where(o, p);
}

query.where(predicates.toArray(new Predicate[predicates.size()]));
users = em.createQuery(query).getResultList();
47
задан Manuel Drieschmanns 7 November 2017 в 15:42
поделиться