我有以下 JPA Criteria API 方法:
public List<AggregationTask> findNonExpiredTasksBy(String entityName, Map<String, String> columnValues) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<AggregationTask> query = cb.createQuery(AggregationTask.class);
Root<AggregationTask> root = query.from(AggregationTask.class);
Predicate entityNamePredicate = cb.equal(root.get("edaEntityName"), entityName);
Predicate columnPredicate = cb.conjunction();
if (columnValues != null && !columnValues.isEmpty()) {
List<Predicate> columnConditions = new ArrayList<>();
for (Map.Entry<String, String> entry : columnValues.entrySet()) {
Predicate condition = cb.and(
cb.equal(root.get("edaEntityColumnName"), entry.getKey()),
cb.equal(root.get("edaEntityColumnValue"), entry.getValue())
);
columnConditions.add(condition);
}
columnPredicate = cb.or(columnConditions.toArray(new Predicate[0]));
}
Predicate expiresAtPredicate = cb.greaterThan(root.get("expiresAt"), cb.currentTimestamp());
query.where(cb.and(entityNamePredicate, columnPredicate, expiresAtPredicate));
return entityManager.createQuery(query).getResultList();
}
这将产生以下查询:
select
*
from
aggregation_tasks at1_0
where
at1_0.eda_entity_name =?
and
(
at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
or at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
or at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
or at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
or at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
or at1_0.eda_entity_column_name =?
and at1_0.eda_entity_column_value =?
)
and at1_0.expires_at > localtimestamp
问题是我需要使用括号将以下条件对分组OR
:
and
(
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
or
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
or
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
or
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
or
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
or
(at1_0.eda_entity_column_name =? and at1_0.eda_entity_column_value =?)
)
我的代码中哪里做错了?我该如何解决?
更新
我使用基于字符串连接的 JPQA 查询重新实现了该方法:
public List<AggregationTask> findNonExpiredTasksBy(String entityName, Map<String, String> columnValues) {
StringBuilder sql = new StringBuilder("SELECT * FROM aggregation_tasks WHERE eda_entity_name = :entityName ");
sql.append("AND expires_at > CURRENT_TIMESTAMP ");
if (MapUtils.isNotEmpty(columnValues)) {
sql.append("AND (");
int count = 0;
for (Map.Entry<String, String> entry : columnValues.entrySet()) {
if (count > 0) {
sql.append(" OR ");
}
sql.append("(")
.append("eda_entity_column_name = :columnName" + count)
.append(" AND eda_entity_column_value = :columnValue" + count)
.append(")");
count++;
}
sql.append(") ");
}
Query query = entityManager.createNativeQuery(sql.toString(), AggregationTask.class);
query.setParameter("entityName", entityName);
if (columnValues != null && !columnValues.isEmpty()) {
int count = 0;
for (Map.Entry<String, String> entry : columnValues.entrySet()) {
query.setParameter("columnName" + count, entry.getKey());
query.setParameter("columnValue" + count, entry.getValue());
count++;
}
}
return query.getResultList();
}
查询工作正常。所以我仍然不明白我在 JPA Criteria API 中对此逻辑的版本做错了什么...