Mybatis-plus一对多 分页映射
在开发中,mybatis一对多分页映射遇到数据不符的问题。
一对多
订单表中,一条订单记录可能有多个商品,通过商品id关联。订单信息需查出商品详细信息等,订单与商品属于一对多的关系。
mybatis在mapper.xml定义resultMap使用<collection>标签实现一对多。
在开发过程中,查询数据会涉及到分页,也许出现这种情况:在mysql中执行语句返回10条记录,但mybatis一对多映射后,可能会返回7、8条记录,导致返回total数量不准确。
原因:
分页是mysql执行,一对多转换是在mybatis层面
如何解决:
mybatis存在子查询,如果我们只查询一对多中的一 就不存在分页问题了,所以先查一,再查询collection的多。
以前使用left join多表查询,只需要一条sql,现变成了多条sql,子查询如何传递关联条件?
介绍下collection标签属性:
- property 与result标签中的property类似
- javaType 一般为ArrayList或是java.util.ArrayList
- ofType 子集合实体类型,即关联查询select对应返回的类
- select 子查询id
- column 数据库的列名或者列标签别名,往子查询参数传递。注意:在处理组合键时,您可以使用column="{子属性1=主查询属性1,子属性2=主查询属性2}”这样的语法,设置多个列名传入到嵌套查询语句。这就会把prop1和prop2设置到目标嵌套选择语句的参数对象中。
💡
使用column可解决参数传递问题,子查询使用#{}取值。注意主查询属性要select出来,因为先执行主查询,再挨个执行子查询。
mybatis分页数据不准确的问题折腾好长时间,通过不断查资料以及调试,终于搞定了。
完整mapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sam.mapper.DiagnosePlanMapper">
<!-- 通用查询映射结果 -->
<resultMap id="diagnoseDeviceResultMap" type="com.sam.vo.DiagnosePlanVO">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="diagnose_slot" property="diagnoseSlot"/>
<result column="diagnose_type" property="diagnoseType"/>
<result column="period_type" property="periodType"/>
<result column="create_user" property="createUser"/>
<result column="create_dept" property="createDept"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="start_time" property="startTime"/>
<result column="end_time" property="endTime"/>
<collection property="weekTime" javaType="java.util.ArrayList" ofType="com.sam.entity.DiagnosePeriodWeek" select="selectPeriodWeek" column="id">
<id property="id" column="w_id" />
<result column="week_diagnose_id" property="diagnoseId"/>
<result column="week" property="week"/>
<result column="week_start_time" property="startTime"/>
<result column="week_end_time" property="endTime"/>
</collection>
<collection property="deviceList" javaType="java.util.ArrayList" ofType="com.sam.entity.DiagnoseDevice" select="selectDevice" column="id">
</collection>
</resultMap>
<select id="selectDiagnosePlanPage" resultMap="diagnoseDeviceResultMap">
select * from diagnose_plan where is_deleted = 0
</select>
<select id="selectDiagnoseList" resultMap="diagnoseDeviceResultMap">
SELECT bdp.*,
bdpm.start_time, bdpm.end_time, bdpm.diagnose_id
FROM diagnose_plan bdp
LEFT JOIN diagnose_period_month bdpm on bdpm.diagnose_id = bdp.id and bdp.period_type = 2
WHERE
bdp.is_deleted = 0
<if test="plan.name != null and plan.name != ''">
AND bdp.`name` LIKE CONCAT('%',#{diagnosePlan.name},'%')
</if>
<if test="diagnosePlan.periodType != null and diagnosePlan.periodType != ''">
AND bdp.period_type = #{diagnosePlan.periodType}
</if>
<if test="diagnosePlan.id != null and diagnosePlan.id != ''">
AND bdp.id = #{diagnosePlan.id}
</if>
<if test="diagnosePlan.status != null and diagnosePlan.status != ''">
AND bdp.`status` = #{diagnosePlan.status}
</if>
ORDER BY bdp.update_time desc
</select>
<select id="selectPeriodWeek" resultType="com.sam.entity.DiagnosePeriodWeek">
SELECT * FROM diagnose_period_week WHERE diagnose_id = #{id}
</select>
<select id="selectDevice" resultType="com.sam.entity.DiagnoseDevice">
SELECT * FROM diagnose_device WHERE diagnose_id = #{id}
</select>
</mapper>