Reputation: 8146
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.
Upvotes: 1
Views: 2491
Reputation: 2841
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));
}
Upvotes: 2