Столбцы дочерних сущностей Spring JPA CriteriaQuery - PullRequest
1 голос
/ 29 мая 2020

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

Вот код, который работает нормально:

    public <T> List<T> findDataByConfiguration(Specification<T> specification, 
        Class clazz, List<String> selectColumns, 
        List<String> aggregationColumns, List<String> groupByColumns) {
        CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
        CriteriaQuery<Tuple> query = criteriaBuilder.createTupleQuery();
        Root<T> root = query.from(clazz);

        List<Selection<?>> multiSelectColumns = new ArrayList<>();
        for (String s : selectColumns) {
            multiSelectColumns.add(root.get(s).alias(s));
        }

        for (String s : aggregationColumns) {
            multiSelectColumns.add(criteriaBuilder.sum(root.get(s)).alias(s));
        }

        List<Expression<?>> groupByColumnsList = new ArrayList<>();
        for (String s : groupByColumns) {
            groupByColumnsList.add(root.get(s));
        }

        query.groupBy(groupByColumnsList);
        query.multiselect(multiSelectColumns);
        query.where(specification.toPredicate(root, query, criteriaBuilder));

        List<Tuple> resultList = this.entityManager.createQuery(query).getResultList();

        // resultList processing
    }

Этот код работает нормально, когда я хочу получить данные класса плоской сущности. Но когда я пытаюсь добавить поле дочерних объектов в select / aggregate / group, появляется сообщение об ошибке:

java .lang.IllegalArgumentException: невозможно найти атрибут с заданным имя [child.id] в этом ManagedType [com.sup.as.data.entity.co.Annual]

// annotations
public class Annual {
    private Long id;
    private String fp;
    private ID iDetails;
    // getter-setter
}

public class ID {
    private Long id;
    private BigDecimal amount;
    // getter-setter

    public String giveMeData() {
        if(id != null && amount != null) {
            return "FILED";
        } else {
            return "NOT FILED";
        }
    }
}

теперь предположим, что мне нужно поле Annual.id, Annual. fp, SUM (Annual.iDetails.amount), Annual.iDetails.giveMeData

Итак, можно ли добавить столбцы дочерних сущностей в select / aggregate / group by? Если кто-то использовал решение такого типа, пожалуйста, помогите мне решить эту проблему.

1 Ответ

2 голосов
/ 29 мая 2020

Если некоторые имена столбцов разделены точками (например, child.id), вы должны использовать root.get("child").get("id") вместо root.get("child.id")

Вам нужен такой метод

private Path<Object> getPath(Root<?> root, String columnPath) {

    if(!columnPath.contains(".")) {
       return root.get(columnPath);
    }

    String[] levels = columnPath.split(".");  
    Path<T> path = root;
    for(String level : levels) {
        path = path.get(level);
    }

    return path;
}

Затем используйте его для selectColumns, aggregationColumns и groupByColumns таким образом

for (String s : selectColumns) {
   multiSelectColumns.add(getPath(root, s).alias(s));
}
...