У меня есть объект, который состоит из полей String и Date.
Как пользователь, заинтересованный в произвольном выборе, мне нужно построить запрос, который может содержать произвольное количество условий в предложении WHERE.
Я хочу использовать JPA API.
Полученный код выглядит следующим образом:
/**
*
* @param start 1st result
* @param size result set max size
* @param filters WHERE search conditions. Key - entity field (column name), Value - search string or date range
*/
public List<Entity> fetchEntities(int start, int size,
Map<String, Object> filters) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Entity> criteriaQuery = cb.createQuery(Entity.class);
Root<Entity> root = criteriaQuery.from(Entity.class);
applyFilters(filters, cb, criteriaQuery, root);
CriteriaQuery<Entity> select = criteriaQuery.select(root);
TypedQuery<Entity> query = em.createQuery(select);
query.setFirstResult(start);
query.setMaxResults(size);
return query.getResultList();
}
private void applyFilters(Map<String, Object> filters, CriteriaBuilder cb, CriteriaQuery<?> criteriaQuery, Root<?> root) {
if (filters != null && !filters.isEmpty()) {
List<Predicate> predicates = new ArrayList<>();
for (Map.Entry<String, Object> entry : filters.entrySet()) {
String fieldName = entry.getKey();
Object value = entry.getValue();
if (value == null) {
continue;
}
Predicate p;
if (Entity.isDateField(fieldName)) {
DateRange dateRange = (DateRange) value;
p = cb.between(root.get(fieldName), dateRange.getStart(), dateRange.getEnd());
} else {
Expression<String> expr = root.get(fieldName).as(String.class);
p = cb.like(cb.lower(expr),
"%" + value.toString().toLowerCase() + "%");
}
predicates.add(p);
}
if (!predicates.isEmpty()) {
criteriaQuery.where(cb.and(predicates.toArray(new Predicate[0])));
}
}
}
Я заново изобретаю колесо?
Есть ли более простые решения, чем приведенный выше код?