「本当の」動的なJPA CriteriaBuilder
を作成する必要があります。私は文でMap<String, String>
を得ます。それは次のようになります。本当に動的なJPA CriteriaBuilder
name : John
surname : Smith
email : [email protected]
...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
述語を追加する可能性がないようないくつかのペアがequal
を必要とし、他のいくつかのlike
ので、ルックスと、それはさえ十分ではありません:ありor
と余分な文はtype : 1;4;7
のように含ま可能性がここに値のように分割し、文を作成する必要があります。UPDATEおよびソリューション は二つのリスト、最初のリストを手に入れた
<rest of statement> AND (type = 1 OR type = 4 OR type = 7)
ANDのためにうまくいく。第二のリストには含まれていOR 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();
OK、私のANDステートメントが動作するためです。 2番目のリストを作成し、そのリストにORステートメントを格納します。結局、私は何をしますか?どちらのタイプのステートメントでも、リストtogehterの両方の結果をANDでコピーします。 私の 'orPredicates'リストには正しい要素が含まれています。このリストをクエリに追加するだけでも、すべてのステートメントはANDでまとめられます。 – Felix
CriteriaBuilderで 'or'と' and'メソッドを呼び出すことによって、結合詞(and)を作成するのと同じ方法で(or)作成することができます。戻り値はどちらの場合も単一の「述語」です。何らかの複雑なグループ化がない場合は、結果の2つの述語に対して 'and'を呼び出し、' where'の結果を使用してください。 – kostja
主な質問が更新され、私の解決策が掲載されました。 – Felix