【问题标题】:EJBQL - How to sort query results by a field in LEFT JOINEJBQL - 如何按 LEFT JOIN 中的字段对查询结果进行排序
【发布时间】:2026-02-02 21:15:01
【问题描述】:

我有以下课程(为清楚起见进行了简化):

Class Top {
  InternationalStringType name;
}

Class InternationalStringType {
  List<LocalizedStringType> localizedString; 
}

Class LocalizedStringType {
  String value;
}

以下 EJBQL 查询成功检索所有 Top 实例及其子对象填充:

SELECT DISTINCT Object(t) FROM Top t LEFT OUTER JOIN t.name nm LEFT OUTER JOIN nm.localizedString nm_ls

我想修改上面的查询,使结果按 Top.name.localizedString.value 排序

执行此操作的正确语法是什么?我尝试了以下查询,但得到“错误:对于 SELECT DISTINCT,ORDER BY 表达式必须出现在选择列表中”

SELECT DISTINCT Object(t) FROM Top t LEFT OUTER JOIN t.name nm LEFT OUTER JOIN nm.localizedString nm_ls ORDER BY nm_ls.value ASC

我不清楚在 ORDER BY 子句的选择列表中放置什么。

无论我在逗号后面放什么,在 Object(t) 之后的“,”都会出现错误:

SELECT DISTINCT Object(t), Object(nm_ls) FROM Top t LEFT OUTER JOIN t.name nm LEFT OUTER JOIN nm.localizedString nm_ls ORDER BY nm_ls.value ASC

如果它相关,我的 JPA 实现是休眠 3.6.4.Final。 TIA 为您提供帮助。

【问题讨论】:

    标签: ejbql


    【解决方案1】:

    ORDER BY 子句中使用的字段必须是 CMP 字段,不能是实体标识符或 CMR 字段。此外,您必须注意您在 ORDER BY 子句中指定的 CMP 字段。如果查询选择实体集合,则 ORDER BY 子句只能与所选实体类型的 CMP 字段一起使用。例如下面的查询是非法的,因为 ORDER BY 子句中使用的 CMP 字段不是所选实体类型的字段。

    选择对象(c) 来自客户作为 c 由 c.address.city 订购

    因为city CMP 字段不是Customer EJB 的直接CMP 字段,所以不能在ORDER BY 子句中使用它。您可以在 ORDER BY 子句中使用的唯一 CMP 字段是选择的实体类型的直接 CMP 字段。这是不合理的限制。

    类似的限制适用于 CMP 结果。 ORDER BY 子句中使用的 CMP 字段必须与 SELECT 子句中标识的 CMP 字段相同。例如,以下查询是非法的,因为 SELECT 子句中标识的 CMP 与 ORDER BY 子句中使用的不同。

    选择 c.address.city 来自客户作为 c 按 c.address.state 订购

    在上面的查询中,我们想要一个按州排序的所有城市的列表。不幸的是,这是非法的。如果您使用城市 CMP 字段进行选择,则不能按州 CMP 字段进行排序。

    我听说第二个限制可能是由于主要 RDBS 系统之一的限制而强加给我们的,该系统无法按 select 子句中不存在的任何列进行排序 - 请记住,EJB QL 被编译为本机查询语言,在 RDBS 中是 SQL。主要供应商的限制将成为创建任何抽象的一个因素 - 最小公分母将占上风。

    【讨论】:

    • 我从下面的文章theserverside.com/news/1321184/…得到了答案,在这里我对你的问题进行了解释,我希望这篇文章能说明这一点。
    • 我没有使用任何 EJB。我只使用使用 JPA(休眠实体管理器)持久化的 POJO。在这种情况下,CMP 和 CMR 是什么意思?
    【解决方案2】:

    只需删除 SELECT 子句中的 DISTINCT 限定符,我就可以使 ORDER BY 子句与我的查询一起使用。我不确定我是否理解其中的要点,但以下修改后的查询效果很好!

    SELECT t FROM Top t LEFT JOIN t.name nm LEFT JOIN nm.localizedString nm_ls ORDER BY nm_ls.value ASC
    

    我现在得到了一个结果集,其中包含按我希望的 Top.name.localizedString.value 属性排序的 Top 实例。

    现在,如果有人能解释为什么 DISTINCT 不起作用,那就太好了。谢谢。

    【讨论】:

    • 您正在强制连接到作为集合的本地化字符串。这意味着对于 1 个单个实体,将有 X 个唯一行(每个引用的本地化字符串一个),所有这些都是完全构建该实体所必需的。由于所有 X 都是不同的,因此 distinct 不会产生您想要的效果 - 即为您的 Top 实体返回单个结果。 JPA 要求回读的每一行都以实体的形式返回,但一些 JPA 提供者可以允许通过本机 api 进行过滤。