Можно ли добавить count (*) и groupBy в спецификацию Spring Data Jpa? - PullRequest
0 голосов
/ 05 ноября 2019

Я пишу приложение, используя Spring Boot и Spring Data Jpa.

У меня есть метод, который использует RSQL (я использую this library) и спецификацию для вызова фильтра сгде пункты к БД.

Мой репозиторий:

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();, но он выбирает все столбцыв любом случае.

Это работает, если я использую @Query("query"), где я определяю, какие столбцы выбрать, но мне нужно, чтобы он работал, используя Criteria Api / Specification.

1 Ответ

1 голос
/ 05 ноября 2019

Вы можете создать свой собственный класс 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));  
...