ResultMap collection多层嵌套使用

ResultMap collection多层嵌套使用

ResultMap介绍

在Mybatis使用中,ResultMap是最复杂的一种结构,也是功能最强大的结构之一。通过ResultMap能够将复杂的1对多的结果集映射到一个实体当中去,可以借助Mybatis来将复杂结构的数据对象映射到一个结果集中组装好。

结构

ResultMap有3个属性,如下:

<resultMap id="studentMap" type="User"  extends="userMap"  ></resultMap>
名称说明
idresultMap标识,区分不同的resultMap
typeresultMap的属性,返回的类型
extends继承的resultMap,类似类的继承,resultMap也可以继承

子元素

名称说明
id子元素中的id属性扮演主键作用指定了该属性,则查询结果会以该属性字段为主键,允许多个主键,多个主键称为联合主键
result返回结果字段,一般一个字段对应一个result
collection表示一对多关系,一般用于结果集中的集合属性,如List
association表示一对一关系
discriminator鉴别器,根据实际选择来采用哪个类别作为实例
constructor配置构造方法

id和result存在一些相同的属性:

property:映射的POJO属性名,如果column元素相同,会自动映射到POJO上

column:sql查询的列名

javaType:配置java的类型,可以是特定的类完全限定名或Mybatis上下文别名

jdbcType:配置数据库类型,一般不需要限定,Mybatis已经为我们做了此工作

typeHander:类型处理器,允许你使用特定的处理器来覆盖默认处理器。需要制定jdbcType和javaType相互转换规则

使用场景

举例:
查询一个复杂的结构,真实场景是不确定度详情信息,一个不确定度详情包含10项列表信息汇总,其中多项是list集合,list中依旧嵌套list,如图所示,此例子只演示2个比较复杂的list
在这里插入图片描述
standardList是标准溶液列表,结构中standardSigns也是list结构,包含多个数值:

描述
equipList是设备列表,每个设备中包含多个内容 contentDatas:

在这里插入图片描述
每个contentDatas中包含多个计算值信息calDatas:

在这里插入图片描述
最复杂的结构如上所示,接下来说如何实现。

实现方式一

一开始我是使用以前的办法,一个sql语句通过左连接将所有表关联起来,然后只使用一个resultMap让mybatis自己去映射关系。

 <select id="getUncertainDataById1"  resultMap="calDataMap1" >
        SELECT
            a.id,
            a.urel,
            a.inclusion AS k,
            a.selected_c AS selectedC,
            a.detectability,
            a.item,
            sar.`value` AS sampleC,
            sac.`value` AS sampleSign,
            bar.`value` AS backData,
            bar.inclusion AS backData_k,
            auto.name AS autoName,
            auto.accuracy AS accuracy,
            auto.inclusion AS auto_k,
            a.standard_c AS standardC,
            a.rel_uncertainty AS relUncertainty,
            a.uncertainty,
            a.backData_critical,
            a.backData_isBack,
            a.backData_confidence,
            a.standard_inclusion,
            a.backData_avg,
            a.unit,
            a.sampleSign_avg,
            a.line_a,
            a.line_b,
            a.line_r,

            eq.id AS eqid,
            eq.`name`,
            eq.dimension,
            eq.volume,
            eq.inclusion AS eq_k,
            eq.origin,
            eqr.id AS rid,
            eqr.`value` AS content,
            eqr.inclusion,
            eqc.row AS crow,
            eqc.`value`,
            eqc.sort,
            eqc.description,

			str.id  AS strid,
            str.`value` AS standardC,
            stc.`value` AS standardSign

        FROM
            t_uncertain a
        -- 关联样品数据
        LEFT JOIN t_uncertain_row sar ON a.id = sar.`code`
        AND sar.type = 2
        LEFT JOIN t_uncertain_column sac ON sac.`row` = sar.id
        -- 关联回收率数据
        LEFT JOIN t_uncertain_row bar ON a.id = bar.`code`
        AND bar.type = 4
        LEFT JOIN t_uncertain_column bac ON bac.`row` = bar.id
        -- 关联自动进样器
        LEFT JOIN t_uncertain_equip auto ON a.id = auto.`code`
        AND auto.origin = 'UN10'
	    -- 仪器
        left join t_uncertain_equip  eq ON eq.`code` = a.id and eq.origin='UN02'
        LEFT JOIN t_uncertain_row eqr ON eq.id = eqr.equip AND eqr.type='3'
        LEFT JOIN t_uncertain_column eqc ON eqc.`row` = eqr.id
        -- 标准曲线标准溶液
		LEFT JOIN t_uncertain_row str ON str.`code` = a.id and  str.type = 1
        LEFT JOIN t_uncertain_column stc ON stc.`row` = str.id
        WHERE
            a.id = #{id}
    </select>

将所有表关联起来查询,查询结果是呈笛卡尔积增加,仅仅查询一个结构该sql结果就已经达到了7200条数据!

之后再通过resultMap进行映射:

 <resultMap id="calDataMap1" type="com.koron.laboratory.web.business.others.bean.CalDataBean">
        <id column="id" property="id"  />
        <!--样品数据-->
        <collection property="sampleList" ofType="com.koron.laboratory.web.business.others.bean.UncertaintyBean" >
            <result column="sampleC" property="sampleC" />
            <result column="sampleSign" property="sampleSign" />
        </collection>

        <!--标准溶液-->
        <collection property="standardList" column="id"  ofType="com.koron.laboratory.web.business.others.bean.UncertaintyBean"  >
            <id  column="strid" property="id" />
            <result column="standardId" property="id" />
            <result column="standardC" property="standardC" />
            <collection property="standardSigns"  ofType="java.lang.Double" >
                <result column="standardSign"  />
            </collection>
        </collection>

        <!--设备数据-->
        <collection property="equipList" column="id" ofType="com.koron.laboratory.web.business.others.bean.EquipUncertainBean" >
            <id  column="eqid" property="id" />
            <result column="name" property="name" />
            <result column="dimension" property="dimension" />
            <result column="volume" property="volume" />
            <result column="eq_k" property="inclusion" />
            <result column="origin" property="origin" />
            <result column="inclusion" property="inclusion" />
            <collection property="contentDatas"  ofType="com.koron.laboratory.web.business.others.bean.UncertaintyBean" >
                <id column="crow" />
                <result column="content" property="content" />
                <result column="inclusion" property="inclusion" />
                <collection property="calDatas"  ofType="com.koron.laboratory.web.business.others.bean.EquipCalBean" >
                    <result column="value" property="value" />
                    <result column="description" property="description" />
                    <result column="sort" property="sort" />
                </collection>
            </collection>
        </collection>
    </resultMap>

这里只保留了几个复杂list结构在resultMap中,其他不是list结构的数据省略了,但是由于也是需要去关联表,所以只要list结构数据量一旦大起来,最终结果都会变得很庞大。

这里需要注意的是 collection中的id属性,当在关联多个表的sql中 id属性作为主键来让mybatis知道该如何映射。即使collection中依旧包含collection,都会通过id属性来判断是否属于一个实体里面,当id相同时,collection中的属性就会自动映射进去。
在这里插入图片描述
这里我遇见的问题就是一开始不知道通过id属性来区分list中,以前遇见的结构最多嵌套1层list,导致这里的多层list嵌套无法识别,仅仅都映射在第一个数据里了。

这种方法虽然能成功将数据映射好,但是将查询的多个结果直接交给mybatis处理,还是比较影响性能的。

实现方式二

将sql拆分成多个select,每个复杂的list结构的select 都用resultMap来接收,这里将standardList和equipList都通过一个select来将查询分开,resultMap具体结构如下:

<resultMap id="calDataMap" type="com.koron.laboratory.web.business.others.bean.CalDataBean">
        <id column="id" property="id"  />
        <!--标准溶液-->
        <collection property="standardList" column="id"  select="getStandardList" />
        <!--样品数据-->
        <collection property="sampleList" ofType="com.koron.laboratory.web.business.others.bean.UncertaintyBean" >
            <result column="sampleC" property="sampleC" />
            <result column="sampleSign" property="sampleSign" />
        </collection>
        <!--设备数据-->
        <collection property="equipList" column="id" select="getEquipList" />
        <!--稀释设备数据-->
</resultMap>

<!--    标准溶液查询resultMap-->
    <resultMap id="standardListMap" type="com.koron.laboratory.web.business.others.bean.UncertaintyBean">
        <id  column="id" property="id" />
        <result column="standardId" property="id" />
        <result column="standardC" property="standardC" />
        <collection property="standardSigns"  ofType="java.lang.Double" >
            <result column="standardSign"  />
        </collection>
    </resultMap>

    <!--    设备查询resultMap-->
    <resultMap id="equipListMap" type="com.koron.laboratory.web.business.others.bean.EquipUncertainBean">
        <id  column="id" property="id" />
        <result column="name" property="name" />
        <result column="dimension" property="dimension" />
        <result column="volume" property="volume" />
        <result column="eq_k" property="inclusion" />
        <result column="origin" property="origin" />
        <result column="inclusion" property="inclusion" />
        <collection property="contentDatas"  ofType="com.koron.laboratory.web.business.others.bean.UncertaintyBean" >
            <id column="crow" />
            <result column="content" property="content" />
            <result column="inclusion" property="inclusion" />
            <collection property="calDatas"  ofType="com.koron.laboratory.web.business.others.bean.EquipCalBean" >
                <result column="value" property="value" />
                <result column="description" property="description" />
                <result column="sort" property="sort" />
            </collection>
        </collection>
    </resultMap>
    


标准溶液和仪器的select如下:

<!--    查询标准溶液信息-->
    <select id="getStandardList" resultMap="standardListMap" >
        SELECT
            str.id,
            str.`value` AS standardC,
            stc.`value` AS standardSign
        FROM
            t_uncertain_row str
        LEFT JOIN t_uncertain_column stc ON stc.`row` = str.id
        WHERE
            `code` = #{id}
        AND str.type = 1
        ORDER BY
            str.id
    </select>

<!--    查询仪器信息-->
    <select id="getEquipList" resultMap="equipListMap" >
         SELECT
            eq.id,
            eq.`name`,
            eq.dimension,
            eq.volume,
            eq.inclusion AS eq_k,
            eq.origin,
            eqr.id AS rid,
            eqr.`value` AS content,
            eqr.inclusion,
            eqc.row AS crow,
            eqc.`value`,
            eqc.sort,
            eqc.description
         FROM t_uncertain_equip  eq
        LEFT JOIN t_uncertain_row eqr ON eq.id = eqr.equip
        LEFT JOIN t_uncertain_column eqc ON eqc.`row` = eqr.id
        where eq.`code`=#{id} AND eqr.type='3' and eq.origin='UN02'
        ORDER BY eq.`name`,eqr.`value`
    </select>

在主体calDataMap中将复杂的collection拆分成select结构,每个select结构有自己独有的resultMap来接收,拆分后每个sql单独执行单独进行数据映射,最终映射好直接插入主体的calDataMap中,这样的做法可以大大的提高效率,以我个人简单的测试结果来看,当方式一查询结果达到7200数据时,方式二可以比方式一快10倍速度左右,当然这个倍数并不准确,但是可以明确的是速度可以快好几倍,效率可以大大提升。
在这里插入图片描述
上图是我进行测试的数据,第一个时间是方式二执行的,第二个是方式一执行的,很明显可以看出2种方式在性能上的差距。

总结

当结构并不是特别复杂的情况下,可以通过使用一个sql将resultMap映射好,当结构中嵌套多层类似list结构的集合时,则需要考虑性能问题,最好将每个collocation拆分开单独对应一个select,这样可以大大提高效率。

  • 14
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
### 回答1: MyBatisCollection多层嵌套可以通过使用<collection>标签来实现。每一层都可以使用<collection>标签,并且可以通过select属性指定查询语句。例如: ``` <resultMap id="nestedResultMap" type="Parent"> <id property="id" column="id"/> <result property="name" column="name"/> <collection property="children" ofType="Child"> <id property="id" column="child_id"/> <result property="name" column="child_name"/> <collection property="grandchildren" ofType="Grandchild"> <id property="id" column="grandchild_id"/> <result property="name" column="grandchild_name"/> </collection> </collection> </resultMap> <select id="selectNested" resultMap="nestedResultMap"> SELECT * FROM parent LEFT JOIN child ON parent.id = child.parent_id LEFT JOIN grandchild ON child.id = grandchild.child_id </select> ``` 希望这个回答对您有帮助! ### 回答2: Mybatis一个Java持久层框架,它支持ORM方式,通过XML或注解的配置方式,将关系数据库中的数据映射到Java对象中,同时提供了灵活的SQL编写方式,使得开发者可以灵活地进行自定义SQL操作。 在Mybatis中,Collection多层嵌套是指在一个实体类中,如果有某个属性对应的数据库列是一个集合或数组类型,则可以通过MybatisCollection标签来实现该属性的映射。同样,如果这个集合或数组中的元素也是一个实体对象,则可以通过在Collection标签中再次使用Mybatis的Nested-select标签来实现多层嵌套的映射。 例如,一个学生有多个选课记录,每个选课记录又包含一个课程和教师信息。如果我们要把这些信息映射到Java对象中,则可以定义一个Student实体对象,其中包含一个名为courses的集合属性,courses中的元素是一个Course对象,Course对象又包含一个Teacher对象。 在映射配置文件中,我们可以使用Collection标签来映射这个courses属性,同时可以在Collection标签中再次使用Nested-select标签来映射Course对象中的teacher属性。具体的配置方式如下: ``` <resultMap id="studentMap" type="Student"> <result property="id" column="id" /> <result property="name" column="name" /> <collection property="courses" ofType="Course"> <result property="id" column="course_id" /> <result property="name" column="course_name" /> <nestedSelect select="selectTeacherByCourseId" resultMap="teacherMap" /> </collection> </resultMap> <resultMap id="teacherMap" type="Teacher"> <result property="id" column="teacher_id" /> <result property="name" column="teacher_name" /> </resultMap> <select id="selectStudentById" resultMap="studentMap"> select * from student where id = #{id} </select> <select id="selectTeacherByCourseId" resultMap="teacherMap"> select * from teacher where id in ( select teacher_id from course_teacher where course_id = #{id} ) </select> ``` 通过这种方式,我们就可以轻松地实现多层嵌套的属性映射,使得实体类中的属性可以与数据库中的多个表关联,提高了数据查询和操作的灵活性。 ### 回答3: MyBatis一个流行的Java持久化框架,在操作数据库时提供了方便和灵活性。当我们需要操作具有多层嵌套结构的数据时,MyBatiscollection标签就派上了用场。 collection标签有以下属性: - property:指定属性名称; - ofType:指定集合元素的类型; - select:指定关联查询的SQL语句; - resultMap:指定结果映射的ID; - javaType:指定Java类型; - column:指定表中的列名。 由于MyBatiscollection标签有那么多属性,所以有时可能会感到混乱。在多层嵌套结构中,我们需要按照我们的需求设置标签中的属性。 假设我们有一个宠物店应用程序,其中包含如下实体类: ```java public class Pet { private Long id; private String name; private String breed; private List<Toy> toys; // 省略getter和setter方法 } public class Toy { private Long id; private String name; // 省略getter和setter方法 } ``` 我们需要从数据库中获取所有宠物和每个宠物所拥有的玩具。在这种情况下,我们需要使用collection标签。 ```xml <!-- 查询所有的宠物和联合查询玩具 --> <select id="getAllPets" resultMap="petResultMap"> SELECT p.id, p.name, p.breed, t.id AS toy_id, t.name AS toy_name FROM pet p LEFT JOIN toy t ON t.pet_id = p.id </select> <!-- 配置resultMap --> <resultMap id="petResultMap" type="Pet"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="breed" column="breed"/> <!-- 用collection标签映射pet有many的toy集合 --> <collection property="toys" ofType="Toy" resultMap="toyResultMap"/> </resultMap> <resultMap id="toyResultMap" type="Toy"> <id property="id" column="toy_id"/> <result property="name" column="toy_name"/> </resultMap> ``` 在上面的示例中,我们定义了两个resultMap来映射查询结果。 petResultMap将查询到的数据映射到Pet实体类中,并使用collection标签映射每个Pet对象的toys属性为一个玩具列表。```ofType="Toy"```属性告诉MyBatis将toys属性映射为Toy对象的列表。Collection标签中resultMap属性设置为```toyResultMap```告诉MyBatis将查询结果映射到Toy对象上。 以上就是MyBatis collection多层嵌套的简单介绍。深入理解和熟练掌握这个标签不仅可以让我们更好地利用MyBatis操作数据,而且可以提高我们的编码效率。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值