在使用 Hibernate 6.4 的项目中,我使用通过 Jakarta persistence API(Hibernate 的依赖项)提供的 Criteria API。但是,我在选择的聚合函数上使用别名时遇到了一个错误。
假设我们有一个具有以下属性的实体 MyEntity :
id
类型为 Integer(此问题不需要它)attr1
attr2
类型为 Integer我们将假设带注释的类已根据此描述正确编写,并在应用程序执行期间正确导入。
我在这里要做的是从与该实体关联的表中选择
attr1
值和 attr2
值之和,并按 attr2
值之和对结果进行排序。
这是与我在项目中编写的代码相对应的代码(我无法给你确切的代码,所以我用这个例子来说明我做了什么):
public class MyClass {
public List<Object[]> myMethod(Session session, String orderAttribute) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<?> cq = cb.createQuery(Object[].class);
Root<MyEntity> root = cq.from(MyEntity.class);
List<Selection<?>> selections = new ArrayList<>();
selections.add(root.get("attr1"));
Selection<Number> sumAttr2 = cb.sum(root.get("attr2")).alias("sumAttr2");
selections.add(sumAttr2);
cq.multiselect(selections);
cq.orderBy(cb.asc(root.get(orderAttribute)));
Query<Object[]> query = session.createQuery(cq);
List<Object[]> result = query.getResultList();
return result;
}
}
当我使用
orderAttribute="attr1"
执行该操作时,它会按预期工作。
但是当我使用 orderAttribute="sumAttr2"
执行查询时,它失败并给出以下错误:
org.hibernate.query.sqm.PathElementException: Could not resolve attribute 'sumAttr2' of 'com.example.MyClass'
我没有在错误情况下生成 SQL 查询,因为它似乎在生成查询时失败,而不是在执行期间失败。然而,我有一个与此对应的案例
orderAttribute="attr1"
的查询:
select me1_0.attr1,sum(me1_0.attr2) from my_entity me1_0 order by 1
我认为问题是由于别名造成的,因为它没有出现在查询中(我没有
sum(me1_0.attr2) as sumAttr2
),当我尝试根据这个缺失的别名对结果进行排序时,出现错误,因为API“认为”它应该是实体的一个属性。
我尝试了多种方法来编写别名,但都不起作用。
Selection<Number> sumAttr2 = cb.sum(root.get("attr2")).alias("sumAttr2");
selections.add(sumAttr2);
Expression<Number> sumAttr2 = criteriaBuilder.sum(root.get("attr2"));
Selection<Number> sumAttr2Selection = sumAttr2.alias("sumAttr2");
selections.add(sumAttr2Selection);
Expression<Number> sumAttr2 = criteriaBuilder.sum(root.get("attr2"));
sumAttr2.alias("sumAttr2");
selections.add(sumAttr2)
你能帮我吗? 我想要的是使用 Criteria API 获得与以下查询等效的内容:
select me1_0.attr1,sum(me1_0.attr2) as sumAttr2 from my_entity me1_0 order by sumAttr2
好的,我找到了解决方案:我们必须使用
CriteriaBuilder.sum()
方法返回的 Expression 对象。
这是我的实现:
public class MyClass {
public List<Object[]> myMethod(Session session, String orderAttribute) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<?> cq = cb.createQuery(Object[].class);
Root<MyEntity> root = cq.from(MyEntity.class);
// Selections
List<Selection<?>> selections = new ArrayList<>();
selections.add(root.get("attr1"));
Expression<Number> sumAttr2 = criteriaBuilder.sum(root.get("attr2"));
Selection<Number> sumAttr2Selection = sumAttr2.alias("sumAttr2");
selections.add(sumAttr2Selection);
cq.multiselect(selections);
// End of selections
// Order
Expression<?> sortIndex;
switch (criteres.getColonneTri()) {
case "sumAttr2":
sortIndex = somme;
break;
// Here, other alias cases if any.
default:
sortIndex = root.get(orderAttribute);
break;
}
cq.orderBy(cb.asc(sortIndex));
// End of order
Query<Object[]> query = session.createQuery(cq);
List<Object[]> result = query.getResultList();
return result;
}
}
Hibernate/JPA 生成的对应 SQL 查询是:
select me1_0.attr1,sum(me1_0.attr2) from my_entity me1_0 order by 2
这里需要注意两件事:
alias()
,根据雅加达持久性规范文档(版本3.1),将在执行时在查询的结果上应用给定的别名。它不会直接在 SQL 查询上应用别名。