JPA 标准 - 不适用于聚合选择的别名

问题描述 投票:0回答:1

在使用 Hibernate 6.4 的项目中,我使用通过 Jakarta persistence API(Hibernate 的依赖项)提供的 Criteria API。但是,我在选择的聚合函数上使用别名时遇到了一个错误。

假设我们有一个具有以下属性的实体 MyEntity :

  • id
    类型为 Integer(此问题不需要它)
  • String 类型的
  • 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
java hibernate jpa criteria criteria-api
1个回答
0
投票

好的,我找到了解决方案:我们必须使用

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

这里需要注意两件事:

  • SQL 查询使用列的索引而不是其名称来执行 order by 操作,
  • 方法
    alias()
    ,根据雅加达持久性规范文档(版本3.1),将在执行时在查询的结果上应用给定的别名。它不会直接在 SQL 查询上应用别名。
© www.soinside.com 2019 - 2024. All rights reserved.