【问题标题】:How to fix the "ORDER BY items must appear in the select list if SELECT DISTINCT is specified" with JPA and Hibernate如何使用 JPA 和 Hibernate 修复“如果指定了 SELECT DISTINCT,则 ORDER BY 项必须出现在选择列表中”
【发布时间】:2023-03-20 13:19:01
【问题描述】:

我在一个项目中工作,其中一项任务是创建动态查询,并可以按相关的惰性 oneToMany 实体属性进行排序。我的第一次尝试是使用 Criteria-api,但是当我需要查询“非相关”字段时,我无法理解它,所以我切换到了普通的 JPQL,在那里我可以更清楚地表达自己

然而,普通的 JPQL 似乎也有问题。用例之一是使用相关实体(例如连接提取)获取 AggregateRoots,其中谓词可以匹配 AggregareRoot 或相关实体属性的值。同样适用于订购部分。现在结果也需要分页

我可以实现所有这些,但是在执行查询时我得到“HHH000104:firstResult/maxResults specified with collection fetch; apply in memory!”。经过一番谷歌搜索后,我最终找到了https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/,在那里得到了解释并提供了 2 个解决方案。第一个解决方案只是查询 AggregateRoots 的 ID:s(没有连接提取),然后使用这些 ID 查询实际的数据图(使用连接提取)。

现在大问题来了,我需要能够按一些聚合根字段或相关实体字段(全部由 UI 指定)排序。我的第一个天真的解决方案只是“从 AggregateRoot 中选择不同的 a.id 作为 id ...”,但是当它需要排序时,我得到了 ORDER BY items must appear in the select list if SELECT DISTINCT is specified。经过一番思考后,我意识到我可以创建所有可能的“排序依据”字段的投影(AggregateRoot.ID 是其中之一,在排序依据子句中用作最后手段以使结果连贯),然后从那里获取 AggregateRoot ID传递给实际的数据查询。但是现在我最终遇到了 ORM 阻抗不匹配的主要问题(如我所见)。基本上最后我有以下类型的 SQL

选择 不同的聚合0_.id 为 col_0_0_, relatedEntity_.name 为 col_6_0_ 从 聚合根聚合0_ 内部联接 相关实体相关实体_ 在 aggregate0_.id=relatedEntity_.aggregate_id 订购 col_6_0_ DESC, col_0_0_ offset 0 rows 仅获取接下来的 3 行

最终会得到结果

<html>
<head>
<style>
table, th, td {
  border: 1px solid black;
}
</style>
</head>
<body>
<table>
<tr>
<td><b>col_0_0_</b></td><td><b>col_6_0_</b></td>
</tr>
<tr>
<td>1</td><td>CCC</td>
</tr>
<tr>
<td>1</td><td>BBB</td>
</tr>
<tr>
<td>2</td><td>AAA</td>
</tr>
</table>
</body>
</html>

所以现在我只有 2 个唯一 ID(而不是 3 个)作为参数传递给实际的数据查询。我还尝试给出提示 HINT_PASS_DISTINCT_THROUGH,如此处所述https://vladmihalcea.com/jpql-distinct-jpa-hibernate/ 但我仍然只得到 2 个聚合根 ID(hibernate-core 版本为 5.4.1.final)。任何建议将不胜感激!

【问题讨论】:

    标签: java hibernate jpa orm spring-data


    【解决方案1】:

    为第一个查询写一个派生表:

    select t.id 
    from (
        select id, col1, col2
        from root_table
        where ...
        order by col1, col2
        fetch first 50 rows only
    ) t
    

    使用从该查询中获取的 id,您可以使用第二个 JPQL 查询来加入获取根实体和子实体,如 this post 中所述。

    【讨论】:

    • 太棒了!我想它应该是 select distinct(t.id) from ... 但似乎在工作。现在我只需要把它翻译成 JPQL :)
    • 你不能把它翻译成 JPQL,你甚至不需要。只需使用本机 SQL。此外,此查询不需要 Distinct,因为您没有加入任何内容。
    • 这是个好问题。但是,由数据库来强制执行该规则,因为查询只是按原样传递给数据库。
    • 似乎有各种 hack 来确保第二个查询将匹配 id 顺序 stackoverflow.com/questions/396748/…
    • 然后在第二个 JPQL 查询中使用 order by 子句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    相关资源
    最近更新 更多