Mybatis-plus一对多 分页映射

在开发中,mybatis一对多分页映射遇到数据不符的问题。

Mybatis-plus一对多 分页映射
一对多
订单表中,一条订单记录可能有多个商品,通过商品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>