JPA Hibernate отображает динамический выбор в пользовательский класс - PullRequest
0 голосов
/ 23 сентября 2019

Я пытаюсь создать пользовательскую группу и агрегировать API, в котором пользователь может группировать по ряду параметров в любой комбинации.

Мой класс проекции подобен

public class ShipmentAggregate {
  private ShipmentMode mode;
  private ShipmentStatus status;
  private Long count;
  private Double weight;

  public static ShipmentAggregate getEmptyAggregate() {
    return ShipmentAggregate.builder().count(0l).weight(Double.valueOf(0)).build();
  }
}

Myрепозиторий похож на

public List<ShipmentAggregate> getAggregate(ShipmentSpecification spec, Set<String> groupBy) {
    final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    final CriteriaQuery<ShipmentAggregate> query =
        criteriaBuilder.createQuery(ShipmentAggregate.class);
    final Root<Shipment> root = query.from(Shipment.class);
    if (groupBy != null) {
      List<Path<?>> grouping = getGroupingExpressions(root, groupBy);
      List<Selection<?>> selectionList = getSelection(criteriaBuilder, root, grouping);
      query
          .multiselect(selectionList)
          .where(spec.toPredicate(root, query, criteriaBuilder))
          .groupBy(grouping.toArray(new Expression<?>[grouping.size()]));
      return entityManager.createQuery(query).getResultList();
    }
    return List.of(ShipmentAggregate.getEmptyAggregate());
  }

  private List<Selection<?>> getSelection(
      final CriteriaBuilder criteriaBuilder, final Root<Shipment> root, List<Path<?>> grouping) {
    List<Selection<?>> selectionList = new ArrayList<>();
    selectionList.addAll(grouping.stream().map(Selection.class::cast).collect(Collectors.toList()));
    selectionList.add(criteriaBuilder.count(root).alias(FIELD_COUNT));
    selectionList.add(
        criteriaBuilder.coalesce(criteriaBuilder.sum(root.get("grossWeight")), 0).alias("weight"));
    return selectionList;
  }

  private List<Path<?>> getGroupingExpressions(Root<Shipment> root, Set<String> groupBy) {
    List<Path<?>> expressions = new ArrayList<>();
    groupBy.forEach(item -> expressions.addAll(findExpression(root, item)));
    return expressions;
  }

  private List<Path<?>> findExpression(Root<Shipment> root, String item) {
    switch (item) {
      case "mode":
        return List.of(root.get("mode"));
      case "status":
        return List.of(root.get("status"));
    }
    // TODO throw exception
    return null;
  }

Если API получает всю группу по полям, он работает, но если по крайней мере один отсутствует, я получаю Невозможно найти подходящее исключение конструктора, так как он пытается создать список результатовиспользуя конструктор.(например, когда groupBy=mode только, но конструктор также содержит status), как правильно отобразить этот динамический выбор, или есть ли способ получить Tuple в качестве результата и сопоставить столбцы (я не устанавливаю псевдонимы)для динамических столбцов)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...