真正动态的 JPA CriteriaBuilder [英] Really dynamic JPA CriteriaBuilder

查看:34
本文介绍了真正动态的 JPA CriteriaBuilder的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个真正的"动态 JPA CriteriaBuilder.我得到一个带有语句的 Map.看起来像:

I need to create a "real" dynamic JPA CriteriaBuilder. I get an Map<String, String> with the statements. It looks like:

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 :-(

I tried to build a big Predicate, which contains all other predicates and add this to the query.where(), but again the predicates overwrites old values. Looks like there is no possibility to add a Predicate instead of change a Predicate :-(

实际项目甚至更复杂,因为有些对需要 equal,而另一些需要 like.这还不够:可能有一个额外的语句,包括 or,如 type : 1;4;7.这里的值必须拆分并创建如下语句:

The real project is even more complicated, because some pairs requires an equal and some other a like. And that is not even enough: There could a extra statement with or included like type : 1;4;7. Here the value have to split up and create a statement like:

<代码><语句的其余部分>AND (type = 1 OR type = 4 OR type = 7)

更新和解决方案有两个列表,第一个 List for AND 效果很好.第二个列表包含 OR 语句,如expected:

UPDATE and SOLUTION Got two lists, first List for AND works well. Second list contains OR statements like 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();

推荐答案

您可以将谓词数组传递给 CriteriaBuilder,决定使用 equallike 随你去.为此,构建一个列表并将列表的内容打包到单个 and 语句中的数组中.像这样:

You can pass an array of predicates to the CriteriaBuilder, deciding on equal or like as you go. For this, build a list and pack the contents of the list into an array in a single and statement. Like this:

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

for (final Entry<String, String> e : myPredicateMap.entrySet()) {

    final String key = e.getKey();
    final String value = e.getValue();

    if ((key != null) && (value != null)) {

        if (value.contains("%")) {
            predicates.add(criteriaBuilder.like(root.<String> get(key), value));
        } else {
            predicates.add(criteriaBuilder.equal(root.get(key), value));
        }
    }
}

query.where(criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])));
query.select(count);

如果您需要区分andor,请使用两个列表.

In case you need to distingiush between and and or, use two lists.

这篇关于真正动态的 JPA CriteriaBuilder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆