在HQL查询中使用联接提取和分组依据

问题描述

我有一个Report实体,其中有一个ReportedTime关系为@OnetoMany的列表。每个ReportedTime一个项目,而Project一个经理。

查询本身(显示底部)可以正常工作。问题是我现在需要将这些实体映射到DTO,并且出于该映射的目的,我需要了解每个ReportedTime中每个Report中的项目。所以我面临一个n + 1问题,我想加入来获取报告的时间和项目:

 @Query(value = "select " +
            "t as timesheetReport," +
            "FUNCTION('string_agg',tlpa.username,',') as projectManagersUsernames," +
            "case when " +
            "   FUNCTION('string_agg',') like concat('%',:username,'%') " +
            "then true else false " +
            "end as assigned " +
            "from TimesheetReport t " +
            "left join fetch t.reportedTimes rt " +
            "left join fetch rt.project p " +
            "left join p.teamleaderAssignments tlp " +
            "left join tlp.account tlpa " +
            "group by t " +
            "having sum(rt.workTime)>0 " +
            "order by assigned desc ")
    List<IReportWithManagers> findAllWithManagers(String username,Pageable pageable);

但我收到此错误

org.postgresql.util.PsqlException: ERROR: column "reportedtimes1_.id" must appear in the GROUP BY clause or be used in an aggregate function

我试图在日志中查看SQL查询,而且在这种情况下,Hibernate似乎也将report_time.id和project.id放在select子句中,但不知道如何对其进行分组?可以解决这个问题吗?

解决方法

收到错误是因为,当然,在获取连接的实体时,您突然试图选择一大堆既不包含在GROUP BY中也没有聚合的新列。

要能够从rtp中选择列,您将需要GROUP BY t,rt,p,不幸的是(据我所知)会更改查询的语义。我会尝试添加单独的JOINS进行抓取和分组:

left join t.reportedTimes rt
left join rt.project p
left join fetch t.reportedTimes rt2
left join fetch rt.project p2
left join p.teamLeaderAssignments tlp
left join tlp.account tlpa
group by t,rt2,p2
having sum(dt.workTime)>0
order by assigned desc

上述问题是,重复的行现在将进入聚合,因此也许您可以使用ARRAY_TO_STRING(ARRAY_AGG(DISTINCT tlpa.username,',')或选择数组并在Java中加入字符串(不确定Hibernate是否支持选择PostgreSQL数组)。框,但您需要选中)。

请注意,我还没有尝试过上述解决方案,所以我不能保证它会起作用。