Mybatis中resultMap的association与collection能否混用?结果映射异常求助
问题:MyBatis 1:n关联查询结果重复,集合未正确聚合
team表与schedule表为1:n关联关系,编写查询球队预约详情的SQL及ResultMap后,返回结果出现多条重复Team对象、dates仅含单个日期的记录,期望单个Team对象对应所有预约日期列表。
现有SQL语句
<select id="getTeamSchdules" resultMap="teamResultMap"> select a.team_id, a.team_name, b.sche_date from team a, schedule b where 1 = 1 and a.STADIUM_ID = b.stadium_id and a.team_id = #{teamId} </select>
现有ResultMap配置
<resultMap id="teamResultMap" type="com.example.api.domain.team.domain.TeamSchedulerInfo"> <association property="team" javaType="com.example.api.domain.team.domain.Team"> <result property="teamId" column="team_id"/> <result property="teamName" column="team_name" /> </association> <collection property="dates" column="stadium_id" javaType="list" ofType="string"> <result column="sche_date" /> </collection> </resultMap>
对应的Java POJO
@Data public class Team { private String teamId; private String teamName; } @Data public class TeamSchedulerInfo { private Team team; private List<String> dates; }
当前错误返回结果
[ { "team": { "teamId": "K04", "teamName": "UNITED" }, "dates": [ "20120324" ] }, { "team": { "teamId": "K04", "teamName": "UNITED" }, "dates": [ "20120414" ] }, { "team": { "teamId": "K04", "teamName": "UNITED" }, "dates": [ "20121117" ] } ]
期望返回结果
[ { "team": { "teamId": "K04", "teamName": "UNITED" }, "dates": [ "20120324", "20120414", "20121117" ] } ]
解决方案
问题核心是MyBatis无法自动识别主表的唯一标识来聚合关联数据,并非association与collection不能同时使用,你的使用方式存在两处关键错误:
1. 给ResultMap配置主对象的唯一标识(id标签)
MyBatis需要通过唯一标识判断哪些行属于同一个主对象,从而聚合集合数据。修改ResultMap,给关联的team对象以及外层TeamSchedulerInfo添加id标签(对应team的主键team_id),同时移除collection的冗余column属性:
<resultMap id="teamResultMap" type="com.example.api.domain.team.domain.TeamSchedulerInfo"> <!-- 配置外层对象的唯一标识,对应team_id --> <id property="team.teamId" column="team_id"/> <association property="team" javaType="com.example.api.domain.team.domain.Team"> <!-- 配置association的唯一标识 --> <id property="teamId" column="team_id"/> <result property="teamName" column="team_name" /> </association> <!-- 无需指定column,MyBatis会根据主标识自动聚合集合数据 --> <collection property="dates" javaType="list" ofType="string"> <result column="sche_date" /> </collection> </resultMap>
2. 优化SQL语句(可选,提升可读性)
原SQL使用隐式内连接,建议改用显式JOIN语法,逻辑更清晰:
<select id="getTeamSchdules" resultMap="teamResultMap"> select a.team_id, a.team_name, b.sche_date from team a join schedule b on a.STADIUM_ID = b.stadium_id where a.team_id = #{teamId} </select>
原理说明
当MyBatis查询到多行结果时,会通过id标签指定的字段判断是否为同一个主对象:
- 若
team_id相同,则将当前行的sche_date追加到已存在的dates集合中 - 若
team_id不同,则创建新的TeamSchedulerInfo对象
这样就能实现单个Team对象对应所有预约日期的聚合效果。
内容的提问来源于stack exchange,提问作者koreanDev
相关产品推荐
相关产品推荐

