首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用JPA规范的Order by @oneToMany字段

使用JPA规范的Order by @oneToMany字段
EN

Stack Overflow用户
提问于 2021-04-06 13:37:34
回答 1查看 295关注 0票数 0

考虑以下各实体-

代码语言:javascript
运行
复制
@Entity
public class Employee {
  @Id
  @GeneratedValue
  private long id;

  private String name;

  @OneToMany(mappedBy = "employee", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  private List<Phone> phones; //contains both "active" & "inactive" phones
}


@Entity
public class Phone {
  @Id
  @GeneratedValue
  private long id;

  private boolean active;
  private String number;
  
  @ManyToOne(fetch = FetchType.LAZY)
  private Employee employee;
}

我需要提取所有的员工,并根据他们拥有的“活动”手机的数量对他们进行排序。请注意,员工可以有活动电话和非活动电话。所以我想要实现的查询是

代码语言:javascript
运行
复制
ORDER BY (SELECT 
        COUNT(phone4_.employee_id)
    FROM
        phone phone4_
    WHERE
        employee4_.id = phone4_.employee_id 
    AND phone4_.active = true
  ) DESC

由于某些原因,我在这里无法使用规范,下面是我使用的代码-

代码语言:javascript
运行
复制
List<Order> orders = new ArrayList<>();
orders.add(cb.desc(cb.size(employee.get("phones"))));
cq.orderBy(orders);

当我运行代码时,生成的查询是

代码语言:javascript
运行
复制
ORDER BY (SELECT 
        COUNT(phone4_.employee_id)
    FROM
        phone phone4_
    WHERE
        employee4_.id = phone4_.employee_id) DESC

我无法向逻辑中添加额外的条件。请建议

EN

回答 1

Stack Overflow用户

发布于 2021-04-06 16:16:15

持久性API规范中所指定的

4.6.16 Subqueries可用于WHERE或HAVING子句。

JPA不支持order子句中的子查询,也不支持select子句中的子查询。

不过,Hibernate ORM在SELECTWHERE子句中支持它们。

因此,您不能编写该查询并与JPA兼容。

不过,这个HQL应该可以工作,它被Hibernate ORM所覆盖:

代码语言:javascript
运行
复制
SELECT e1, (SELECT count(p)
            FROM Phone p
            WHERE p.active = true AND p.employee = e1) as activeCount
FROM Employee e1
ORDER BY activeCount DESC

令人惊讶的是,使用条件编写此查询不起作用:

代码语言:javascript
运行
复制
CriteriaBuilder builder = ormSession.getCriteriaBuilder();
CriteriaQuery<Object> criteria = builder.createQuery();
Root<Employee> root = criteria.from( Employee.class );

Subquery<Long> activePhonesQuery = criteria.subquery( Long.class );
Root<Phone> phoneRoot = activePhonesQuery.from( Phone.class );

Subquery<Long> phonesCount = activePhonesQuery
                .select( builder.count( phoneRoot ) )
                .where( builder.and( builder.isTrue( phoneRoot.get( "active" ) ), builder.equal( phoneRoot.get( "employee" ), root ) ) );

criteria.multiselect( root, phonesCount )
    .orderBy( builder.desc( phonesCount ) );

原因是Hibernate ORM试图按order子句展开子查询,以引用别名。正如我前面提到的,这是不受支持的。

如果不想使用本机查询,我认为HQL是最简单的选择。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66969763

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档