Fel*_*lix 47 java jpa criteria-api jpa-2.0
我需要创建一个"真正的"动态JPA CriteriaBuilder.我得到Map<String, String>了陈述.看起来像:
name : John
surname : Smith
email : email@email.de
...more pairs possible
Run Code Online (Sandbox Code Playgroud)
这是我实现的:
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)
}
Run Code Online (Sandbox Code Playgroud)
我试图构建一个Predicate包含所有其他谓词的big ,并将其添加到query.where(),但谓词再次覆盖旧值.看起来没有可能添加一个Predicate而不是改变谓词:-(
真正的项目更复杂,因为有些对需要一个equal和其他一个like.这还不够:还有一个额外的声明or包括像type : 1;4;7.这里的值必须拆分并创建一个语句,如:
<rest of statement> AND (type = 1 OR type = 4 OR type = 7)
更新和解决方案 有两个列表,第一个AND列表运行良好.第二个列表包含exspected之类的OR语句:
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();
Run Code Online (Sandbox Code Playgroud)
kos*_*tja 58
您可以将一个谓词数组传递给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);
Run Code Online (Sandbox Code Playgroud)
如果您需要在and和之间进行distingiush or,请使用两个列表.
axt*_*avt 19
一种选择是使用具有可变数量的参数的方法可以采用数组的事实:
query.where(predicates.toArray(new Predicate[predicates.size()]));
Run Code Online (Sandbox Code Playgroud)
或者,您可以将它们组合成一个谓词(请注意,如果您不这样做,则不需要像示例中那样创建连接);:
Predicate where = cb.conjunction();
while (column.hasNext()) {
...
where = cb.and(where, cb.equal(userRoot.get(colIndex), colValue));
}
query.where(where);
Run Code Online (Sandbox Code Playgroud)
我一直认为创造像这样的解决方案就像重新发明自行车一样.这里https://github.com/sasa7812/jfbdemo是我的解决方案.它在EclipseLink和Hibernate上进行了测试(EclipseLink在生产中,我们在几个项目中用于简单案例).有时你只需要一个快速的解决方案来制作一个带有排序和过滤的dataTable,没什么好看的.它能够对连接的字段进行过滤和排序,甚至可以对集合进行过滤和排序.Project包含Primefaces上的演示,显示了FilterCriteriaBuilder的功能.在它的核心你只需要这个:
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();
}
Run Code Online (Sandbox Code Playgroud)
从数据库中获取结果.
我真的需要有人告诉我它很有用,并且用于某个地方继续我在这个库上的工作.
| 归档时间: |
|
| 查看次数: |
70590 次 |
| 最近记录: |