我正在使用Spring Boot和Spring Data Jpa编写应用程序。
[我有一个使用RSQL(我使用this库)和Specification的方法来对数据库的where子句进行过滤器调用。
我的存储库:
public interface BaseRepository<M extends BaseModel> extends JpaRepository<M, Long>, JpaSpecificationExecutor<M>{
}
在服务中,我调用存储库:
String filter = "createdDate > 2019-09-04T11:52:59.449";
return repository.findAll(toSpecification(filter), pageable).getContent();
因此,我使用上面的库来生成规范并将其传递到存储库。
现在,我需要按某些字段对结果进行分组。
该问题如何将count和groupBy添加到规范中?或者,也许我需要创建一个谓词,在其中定义此count和groupBy(以某种方式)并据此进行说明?有什么更好的方法呢?
UPDATE#0
我已经设法按部分向结果sql查询添加了一个组。我创建了一个新的规范对象,在该对象中,我按参数定义了所有分组,然后将此规范与原始规范组合。
String filter = "createdDate > 2019-09-04T11:52:59.449";
Specification<M> groupBySpec = new Specification<M>() {
@Override
public Predicate toPredicate(Root<M> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Expression<?>> groupByParams = new ArrayList<>();
groupByParams.add(root.get("param1"));
groupByParams.add(root.get("param2"));
query.groupBy(groupByParams);
return query.getGroupRestriction();
}
};
return repository.findAll(groupBySpec.and(toSpecification(filter)), pageable).getContent();
事实是它总是选择所有列,但我只需要按组选择那些列。
结果是我得到一个SQL异常:ERROR: column "columnName" must appear in the GROUP BY clause or be used in an aggregate function
。
我已经尝试使用像criteriaQuery.multiselect(root.get("column1"), root.get("column2")).distinct(true).getGroupRestriction();
这样的multiselect,但无论如何它都会选择所有列。
[如果我使用@Query("query")
定义了哪些列,但是我需要它使用Criteria Api / Specification才能起作用。
您可以创建自己的GroupBySpecification
类,该类将groupBy表达式添加到其他规范:
public class GroupBySpecification implements Specification {
Specification original;
Parameters parameters; // whatever data needed for calculating groupBy expression
public GroupBySpecification(Specification original, Parameters parameters){
this.original = original;
this.parameters = parameters;
}
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Expression<?> expression = ...; // whatever logic needed to be used on parameters...
criteriaBuilder.groupBy(expression);
return original.toPredicate(root, query, criteriabuilder);
}
}
然后您可以像这样使用它:
String filter = "createdDate > 2019-09-04T11:52:59.449";
return repository.findAll(new GroupBySpecification(toSpecification(filter),parameters),
pageable).getContent();
如果需要count,则调用适当的存储库方法:
repository.count(new GroupBySpecification(toSpecification(filter),parameters));