【问题标题】:Spring JPA CriteriaQuery child entity columnsSpring JPA CriteriaQuery 子实体列
【发布时间】:2020-09-16 22:54:33
【问题描述】:

我正在尝试创建一些动态机制,以使用基于给定类、规范、选择列、聚合列和按列分组的条件查询从数据库中获取数据。

这是运行良好的代码:

    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
    }

当我想获取平面实体类的数据时,此代码工作正常。 但是,当我尝试在选择/聚合/组中添加子实体字段时,它会引发错误:

java.lang.IllegalArgumentException:无法在此 ManagedType [com.sup.as.data.entity.co.Annual] 上找到具有给定名称 [child.id] 的属性

// 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 中添加子实体列? 如果有人做过这种类型的解决方案,那么请帮我解决这个问题。

【问题讨论】:

    标签: java spring-data-jpa aggregate-functions hibernate-criteria


    【解决方案1】:

    如果某些列名以点分隔(例如,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;
    }
    

    然后以这种方式将其用于selectColumnsaggregationColumnsgroupByColumns

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

    【讨论】:

    • 是否可以在 this 中调用方法?假设我有 2 个字段,并且有 1 个方法使用现有的 2 个字段并返回一些结果..
    • 还有一个问题是,如果我将获取子列并将值设置为父列,则子项未初始化,它不会设置子字段的值。
    • 如果没有上下文,这很难理解。举个例子吧
    • 添加了问题。要获取的类结构和字段
    • Annual.iDetails.giveMeData 不是字段而是方法。这里不允许使用root.("iDetails").get("giveMeData")
    猜你喜欢
    • 1970-01-01
    • 2015-04-07
    • 2017-06-01
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 2018-04-13
    相关资源
    最近更新 更多