Question

Need to generate a query like so using JPA. It needs to be dynamic because I don't know till runtime what parameters I'd get.

SQL I'd like from JPA:

select * from foo where a='A' OR b='B' OR c='C' OR (x='X' AND y='Y')

  • Don't know ahead of time if any of 'A', 'B', 'C', 'X', 'Y' will be provided.
  • X and Y should always use 'AND'.
  • If one of the inputs is missing, example, if C is not provided, we should simply eliminate that - query becomes - "select * from foo where a='A' OR b='B' OR (x='X' AND y='Y')

Most of the examples I've come across using JPA are simply using the AND operator when a query is dynamically generated. Either that, or, they are doing it statically using "criteriabuilder.or(..., ..., ...). That won't work in my case.

Was it helpful?

Solution

You can use either CriteriaBilder#disjunction() operator in order to build a Predicate to be dynamically modified:

Integer aValue, xValue, yValue;
Predicate p = cb.disjunction();
if (aValue != null) {
    p = cb.or(p, cb.equal(foo.get("a"), aValue));
}
...
if (xValue != null && yValue != null) {
    p = cb.or(p, cb.and(cb.equal(foo.get("x"), xValue), cb.equal(foo.get("y"), yValue)));
}

Or use an array of predicates:

List<Predicate> predicateArray = new ArrayList<> ();
if (aValue != null) {
    predicateArray.add(cb.equal(foo.get("a"), aValue));
}
...
if (xValue != null && yValue != null) {
    predicateArray.add(cb.and(cb.equal(foo.get("x"), xValue), cb.equal(foo.get("y"), yValue)));
}
Predicate p = cb.or(predicateArray.toArray(new Predicate[] {})));

OTHER TIPS

You can write your query storing that in a String variable where you can append several parts of that respect some condition.

An example:

// This part is always presents
String hql = " SELECT * FROM foo ";
String whereClause = " where ";
String whereCond = "";

if (condition on A is satisfacted) {
    whereCond += "a = 'A'";
}

if (condition on B is satisfacted) {
    if (!whereCond.equals("")) {
        whereCond += " or ";
    }
    whereCond += "b = 'B'";
}

... AND GO ON ...

At the end

String res = hql;
if (!whereCond.equals("")) {
   res += whereClause + whereCond;
}

return res;

Tell me if it's OK

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top