spring 从Sping Boot 3.1.0迁移到3.1.1时,JOIN查询中断

vmdwslir  于 2023-06-28  发布在  Spring
关注(0)|答案(2)|浏览(100)

我正在从Sping Boot 3.1.0迁移到3.1.1,只是一个简单的补丁版本升级。
但是它错误地开始在表上使用JOIN而不是定义的LEFT JOIN。这意味着我得到的结果更少,因为外键是可选的。
回购:

@Query("""
    SELECT ak FROM ApiKey ak
    LEFT JOIN ak.role r
    WHERE ak.projectId = :projectId
    """)
Page<ApiKey> find(@Param("projectId") UUID projectId, Pageable pageable);

我们在role上留下JOIN的原因是因为pageable可以包含role.name上的排序
但是,现在生成了以下查询:

select a1_0.id,a1_0.created_date,a1_0.db_version,a1_0.expiry_date,a1_0.last_used,a1_0.name,a1_0.project_id,a1_0.public_part,a1_0.role_id,a1_0.secret_key_hash,a1_0.updated_date from api_key a1_0 join role r2_0 on r2_0.id=a1_0.role_id where a1_0.project_id=? order by r2_0.name offset ? rows fetch first ? rows only

它有一个规则的连接,这显然是错误的。除了重写SQL,我还能做什么?

xzv2uavs

xzv2uavs1#

从票证开始的随访:
这实际上不是Hibernate,而是Spring Data,它显然会自动删除left join,因为它看不到它的用途,因为sort参数与left join中的别名不一样。然后,它会自动添加一个常规的join,以便能够在实际的role.name排序上进行排序。我猜它是通过在ApiKey中找到role作为字段名来实现的。
我认为一个bug是它没有使用left join而是使用join,因为现在数据由于排序而自动受到限制。这也是一个很大的变化,使在一个小补丁发布。但这里最简单的解决方案是将别名命名为与实体中的字段相同的名称。特别是如果你的页面是由客户端构造的(就像我们的例子),他们不想使用别名缩写作为他们的排序参数。

fivyi3re

fivyi3re2#

如果Role表是seprate表,那么你应该尝试这样做。

SELECT 
    ak
FROM
    ApiKey ak
        LEFT JOIN
    Role r ON ak.role = r.id
WHERE
    ak.id = 1;

如果你想在同一个表上应用leftjoin,那么试试这个

SELECT 
    ak
FROM
    ApiKey ak
        LEFT JOIN
    ApiKey ak1 ON ak.role = ak1.role
WHERE
    ak.id = :projectId;

相关问题