「実際の」動的JPA CriteriaBuilder
を作成する必要があります。ステートメントで_Map<String, String>
_を取得します。次のようになります。
_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
が必要なため、実際のプロジェクトはさらに複雑です。それだけでは十分ではありません:_type : 1;4;7
_のようなor
を含む追加のステートメントがあります。ここでは、値を分割して次のようなステートメントを作成する必要があります。
<rest of statement> AND (type = 1 OR type = 4 OR type = 7)
---(UPDATEおよびSOLUTION 2つのリストを取得しました。最初のANDのリストは適切に機能します。 2番目のリストには、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();
_
述語の配列をCriteriaBuilder
に渡すことができ、equal
またはlike
を決定します。このために、リストを作成し、リストの内容を単一のand
ステートメントで配列にパックします。このような:
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);
and
とor
を区別する必要がある場合は、2つのリストを使用します。
1つのオプションは、可変数の引数を持つメソッドが配列を取ることができるという事実を使用することです。
query.where(predicates.toArray(new Predicate[predicates.size()]));
あるいは、それらを単一の述語に結合することができます(実行しない場合は、例のように接続詞を作成する必要がないことに注意してください)。
Predicate where = cb.conjunction();
while (column.hasNext()) {
...
where = cb.and(where, cb.equal(userRoot.get(colIndex), colValue));
}
query.where(where);
私はいつも、そのようなソリューションの作成は自転車を再発明するようなものだと考えてきました。ここに https://github.com/sasa7812/jfbdemo が私の解決策です。 EclipseLinkおよびHibernateでテストされました(EclipseLinkは実稼働環境で、いくつかのプロジェクトで単純なケースで使用しました)。場合によっては、並べ替えとフィルタリングを行うだけで簡単なdataTableを作成するための簡単なソリューションが必要なだけです。結合されたフィールド、さらにはコレクションでフィルタリングおよびソートすることができます。プロジェクトには、FilterCriteriaBuilderの機能を示すPrimefacesのデモが含まれています。その中心には、これが必要です:
public List<T> loadFilterBuilder(int first, int pageSize, Map<String, Boolean> sorts, List<FieldFilter> argumentFilters, Class<? extends AbstractEntity> entityClass) {
FilterCriteriaBuilder<T> fcb = new FilterCriteriaBuilder<>(getEntityManager(), (Class<T>) entityClass);
fcb.addFilters(argumentFilters).addOrders(sorts);
Query q = getEntityManager().createQuery(fcb.getQuery());
q.setFirstResult(first);
q.setMaxResults(pageSize);
return q.getResultList();
}
データベースから結果を取得します。
このライブラリでの作業を継続するためにどこかで使用されていることを教えてくれる人が本当に必要です。
述語の場合、新しいArrayListを作成してすべての述語をリストに追加し、最後に述語配列を作成し、リストを述語配列に変換し、直接条件ビルダーに割り当てることができます。where(new Pridicate [])