英文:
Spring JPA CriteriaQuery child entity columns
问题
我正在尝试创建一些动态机制,以基于给定类、规范、选择列、聚合列和分组列的条件查询从数据库中提取数据。
以下是可以正常工作的代码:
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
}
当我想获取扁平实体类的数据时,此代码可以正常工作。
但是,当我尝试在选择/聚合/分组中添加子实体字段时,会引发错误:
java.lang.IllegalArgumentException: Unable to locate Attribute with the given name [child.id] on this ManagedType [com.sup.as.data.entity.co.Annual]
// 注释
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 "FIELD";
} else {
return "NOT FILED";
}
}
}
现在假设我想要字段 Annual.id, Annual.fp, SUM(Annual.iDetails.amount), Annual.iDetails.giveMeData
那么是否可以在选择/聚合/分组中添加子实体的列?
如果有人已经解决了这种类型的问题,请帮助我解决这个问题。
英文:
I am trying to make some dynamic mechanism to fetch data from db using criteria query based on given class, specification, select columns, aggregated columns and group by columns.
Here's the code which is working fine:
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
}
This code is working fine when when I want to fetch data of flat entity class.
But when I am trying to add child entiti'es field in select/aggregate/group by then it's throwing an error:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [child.id] on this 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";
}
}
}
now suppose I want field Annual.id, Annual.fp, SUM(Annual.iDetails.amount), Annual.iDetails.giveMeData
So is it possible to add child entities columns in select/aggregate/group by ?
If anyone have done this type of solution then please help me to resolve this.
答案1
得分: 2
如果某些列名以点分隔(例如 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));
}
英文:
If some of column names are dot-separated (for instance, child.id
) you have to use root.get("child").get("id")
instead of root.get("child.id")
You need method like this
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;
}
Then use it for selectColumns
, aggregationColumns
and groupByColumns
this way
for (String s : selectColumns) {
multiSelectColumns.add(getPath(root, s).alias(s));
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论