可直接翻到最后面看原理部分~
应用场景:
最近在做考勤管理的临时排班,需要根据用户id查询临时排班表记录,临时排班可以嵌套多个计划模版;
mybatis的xml文件如下:
<select id="select" parameterType="userTempPlan" resultMap="userTempPlanMap">
select
user_temp_plan.user_id,
user_temp_plan.scheduled_date,
schclass.start_time schclass_start_time,
schclass.end_time schclass_end_time,
schclass.name schclass_name
from
user_temp_plan,
schedule_class
<where>
user_temp_plan.schclass_id = schclass.id
<!-- 根据userId查询 -->
<if test="userId!=null and userId != ''">
and user_temp_plan.user_id = #{userId}
</if>
</where>
</select>
<resultMap id="userTempPlanMap" type="userTempPlan" extends="BaseResultMap">
<collection property="scheduleClassList" fetchType="lazy" columnPrefix="schclass_" resultMap="com.xxx.dao.ScheduleClassMapper.BaseResultMap" />
</resultMap>
查询之后的结果如下:
{
"id":"id1"
"userId": "userId1",
"scheduledDate": "2019-10-01",
"scheduleClassList": [
{
"name": "新建时间段11",
"startTime": "09:00",
"endTime": "12:00"
},
{
"name": "新建时间段12",
"startTime": "14:00",
"endTime": "18:00"
}
]
},
{
"id":"id2"
"userId": "userId1",
"scheduledDate": "2019-10-01",
"scheduleClassList": [
{
"name": "新建时间段2",
"startTime": "17:00",
"endTime": "20:59"
}
]
}
前端人员说,这个数据不友好,能不能把时间段相同的嵌套在一起,我想起mybatis好像可以根据字段进行嵌套映射,就试了一下:
这里需要根据userId
和scheduledDate
进行嵌套映射,如果数据中userId
和scheduledDate
相同,我们就把查询出来的计划模版进行嵌套;
查询的sql语句不变,但resultMap
需要调整一下:
<resultMap id="userTempPlanMap" type="userTempPlan">
<!-- 根据user_id,scheduled_date进行嵌套映射 -->
<id column="user_id" jdbcType="VARCHAR" property="userId" />
<id column="scheduled_date" jdbcType="DATE" property="scheduledDate" />
<collection property="scheduleClassList" fetchType="lazy" columnPrefix="schclass_" resultMap="com.xxx.dao.ScheduleClassMapper.BaseResultMap" />
</resultMap>
查询之后的结果如下:
{
"userId": "userId1",
"scheduledDate": "2019-10-01",
"scheduleClassList": [
{
"name": "新建时间段11",
"startTime": "09:00",
"endTime": "12:00"
},
{
"name": "新建时间段12",
"startTime": "14:00",
"endTime": "18:00"
},
{
"name": "新建时间段2",
"startTime": "17:00",
"endTime": "20:59"
}
]
}
这个就是前端想要的数据了。
原理
MyBatis在处理结果的时候,会判断结果是否相同,如果是相同的结果,则只会保留第一个结果,所以这个问题的关键点就是MyBatis如何判断结果是否相同。
MyBatis判断结果是否相同时,最简单的情况就是在映射配置中至少有一个id标签,在userMap中配置如下。
<id property=nid" column="id />
我们对id(构造方法中为idArg)的理解一般是,它配置的字段为表的主键(联合主键时可以配置多个id标签),因为MyBatis的resultMap
只用于配置结果如何映射,并不知道这个表具体如何。id的唯一作用就是在嵌套的映射配置时判断数据是否相同,当配置id标签时,MyBatis只需要逐条比较所有数据中id标签配置的字段值是否相同即可。在配置嵌套结果查询时,配置id标签可以提高处理效率。( 如果没配置id标签的话会比对所有字段)
所以我们配置两个<id column="id" property="id" />
即可实现多字段映射。