You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JPA无额外注解实现关联查询:获取部门及学生去重层级列表

适配嵌套结构的JPA实现方案

问题根因

你现在拿到平铺二元组返回的核心原因,是直接做行级关联查询——每个匹配的「部门-学生」记录都会生成一行独立结果,自然无法把同部门下的多个Level值嵌套聚合到同一行部门记录里。
要在不引入额外自定义注解、自定义DTO的前提下拿到目标嵌套结构,只要从聚合查询逻辑和实体关联补全两个点调整即可。

具体调整步骤

  1. 补全实体的双向关联(这是JPA关联映射的标准写法,不属于额外自定义注解)
    你现在只在Student侧定义了指向Department的多对一关联,Department实体里缺少反向的学生集合映射,直接关联查询会取不到部门下的学生列表。在Department类里补充标准的一对多映射即可:
    @OneToMany(mappedBy = "dp")
    private List<Student> students;
    
  2. 替换Repository里的JPQL查询语句
    用JPA原生支持的分组聚合逻辑,把同部门的去重Level值直接聚合成集合,对应查询写法:
    @RestResource(path="/myquery")
    @Query("SELECT d.name, COLLECT(DISTINCT s.Level) FROM Department d JOIN d.students s GROUP BY d.id, d.name")
    List<Object[]> getLevel();
    
    这里的几个关键细节:
    • COLLECT(DISTINCT s.Level)是JPA规范内置的聚合函数,会把当前分组下所有学生的Level值去重后聚合成整数列表,不需要手动处理行拼接
    • 分组条件同时写d.id和d.name,是为了兼容开启了only_full_group_by的MySQL等数据库的SQL校验规则,避免查询报错
    • 从Department实体出发做关联查询,能避免从Student出发查询时漏过没有学生的空部门的场景

最终返回结构匹配验证

Spring Data JPA 在序列化List<Object[]>类型的返回值时,会严格按照查询字段的顺序生成嵌套结构:

  • 数组第一个元素为字符串类型的部门名称
  • 数组第二个元素为聚合生成的Level值列表
    最终输出的JSON结构完全匹配你的预期:
[
  [
    "Dep1",
    [1, 2, 3]
  ],
  [
    "Dep2",
    [1]
  ]
]

常见踩坑提醒

  • 不要直接写SELECT d.name, s.Level FROM ... GROUP BY d.name, s.Level,这种写法还是会把每个Level值单独生成一行,回到最初的平铺二元组结果
  • 不要遗漏DISTINCT关键字,否则聚合出来的Level列表会包含重复值,不符合去重的要求

内容的提问来源于stack exchange,提问作者Nova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 14:57:03