Spring JPA CriteriaQuery 子实体列

huangapple go评论82阅读模式
英文:

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 &lt;T&gt; List&lt;T&gt; findDataByConfiguration(Specification&lt;T&gt; specification, 
        Class clazz, List&lt;String&gt; selectColumns, 
        List&lt;String&gt; aggregationColumns, List&lt;String&gt; groupByColumns) {
    	CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
        CriteriaQuery&lt;Tuple&gt; query = criteriaBuilder.createTupleQuery();
        Root&lt;T&gt; root = query.from(clazz);
    
        List&lt;Selection&lt;?&gt;&gt; multiSelectColumns = new ArrayList&lt;&gt;();
        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&lt;Expression&lt;?&gt;&gt; groupByColumnsList = new ArrayList&lt;&gt;();
        for (String s : groupByColumns) {
            groupByColumnsList.add(root.get(s));
        }
    
        query.groupBy(groupByColumnsList);
        query.multiselect(multiSelectColumns);
        query.where(specification.toPredicate(root, query, criteriaBuilder));
    
        List&lt;Tuple&gt; 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 &amp;&amp; amount != null) {
			return &quot;FILED&quot;;
		} else {
			return &quot;NOT FILED&quot;;
		}
	}
}

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(&quot;child&quot;).get(&quot;id&quot;) 代替 root.get(&quot;child.id&quot;)

您需要像这样的方法:

private Path&lt;Object&gt; getPath(Root&lt;?&gt; root, String columnPath) {

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

    String[] levels = columnPath.split(&quot;.&quot;);  
    Path&lt;T&gt; path = root;
    for(String level : levels) {
        path = path.get(level);
    }

    return path;
}

然后在以下方式中将其用于 selectColumnsaggregationColumnsgroupByColumns

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(&quot;child&quot;).get(&quot;id&quot;) instead of root.get(&quot;child.id&quot;)

You need method like this

private Path&lt;Object&gt; getPath(Root&lt;?&gt; root, String columnPath) {

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

    String[] levels = columnPath.split(&quot;.&quot;);  
    Path&lt;T&gt; 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));
}

huangapple
  • 本文由 发表于 2020年5月29日 19:22:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/62084797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定