深入浅出Mybatis:鉴别器级联的原理

先来看两段代码:
public class MaleStudenBean extends StudentBean{
    private List<StudentHealthMaleBean> studentHealMaleList = null;
    /******getter and setter******/
}
public class FemaleStudentBean extends StudentBean{
   private List<StudentHealthFemaleBean> studentHealthFemaleList = null;
   /***getter and setter***/
}
分析代码:
//根据MaleStudenBean 和 StudentBean这是两个Bean对象
//MaleStudenBean 将拥有 StudentBean的属性以及相应的getter和setter方法
//比如: id,name,sex,studcardId(学生证号)
//studentHealMaleList表示一个集合对象,且集合中每一个对象都是一个StudentHealthMaleBean对象
//问一个问题?StudengHealthMaleBean中有哪些属性呢?
//可想而知:除了编号(id)和备注(note)外,应该有:stuId,checkDate,xin,gan,pi,fei,shen,qianliexian
//对于一个bean通常就是一张表映射的对象
//一个bean我们首先关心的问题应该是,它有哪些属性?与表中列一一对应
//这里我们还观察出一个知识:就是可以将一个bean作为另一bean的属性,
//这种做法的常见形式有两种,第一中就是,直接作为单个属性,另一中是作为集合属性
//我觉得这里作为单个属性不是才符合实际么?
//这个问题先放下,为什么要这么做呢?(一个bean作为另一个bean的属性?)
//对于MaleStudenBean,它有哪些属性呢?
//id,name,sex,studentHealMaleList
//再注意一件事情:StudentBean,StudentHealthMaleBean都是有实际表对应的
//而这个bean完全没有实际的表与之对应
//这里最让人费解的就是:不应该用集合属性啊,用单个属性才应该是正解啊
//这个问题先放到这里,一会再作出解答
//原因是什么呢?告诉你包因为错了啊
public class MaleStudenBean extends StudentBean{
    /*错误代码*/
    private List<StudentHealthMaleBean> studentHealMaleList = null;
    /*正确代码*/
    private StudentHealthMaleBean studentHealMaleList = null;
    /******getter and setter******/
}


//按照上面的分析来研究一下下面这个bean: FemaleStudentBean
//首先,分析这个bean有那些属性? id,name,sex,note,studentHealthFemaleList
//其次,分析这个bean对应哪一张表:没有实际的表与之对应,如果非要说对应的话,
//那么可以说它对应两张表:StudentBean,StudentHealthFemaleBean
//可以说,这个bean就是把这两个bean整合在一起
//那么整合在一起,这个bean表示什么意思呢? 一个女生的健康状况!!!
//发现没有,当思考某个东西感到困惑的时候,转换一下思考的方向和对象,这比死咬住它不放更有用
//死咬住不放,就是钻牛角尖思考,这种思考花费时间很多但收获和进展甚微
//当然到这里我们依然不知道为什么还是作为集合属性出现啊
//那就把这个困惑放在这里
public class FemaleStudentBean extends StudentBean{
   private StudentHealthFemaleBean studentHealthFemaleList = null;
   /***getter and setter***/
}
总结:分析一个bean时,请思考:有哪些属性? 对应那张表? 或对应哪几张表?
再分析一下bean都是干嘛的?(向上分析问题):是不是都是存储数据的
数据怎么来的呢?通过到执行对应的mapper得到的,得到结果后,映射到bean中的
进行了向上分析之后,
来向下分析和思考一下:
我要怎么搞到StudentBean的数据和StudentHealthFemaleBean的数据?
我又怎么把搞到的数据填入到FemaleStudentBean中?
这个问题好像很难想
我们想象其他的问题吧
1.StudentBean是不是对应一个dao这个dao是不是对应一个mapper
2.StudentHealthFemaleBean是不是对应一个dao,这个dao是不是对应一个mapper
3.FemaleStudentBean是不是也要对应一个dao,这个dao是不是也应该有一个mapper呢?
我觉得应该是,如果要往FemaleStudentBean里面填数据只能借助mapper的映射机制了
因为mapper的映射机制就干两件事情:向数据库查询数据,然后把数据回填到对应的bean中
接下来,问题就出现了,这个bean的mapper该如何实现呢?(假设我的dao已经写好了对应的方法了)

注意:之前的那种思考角度已经被证明是个死胡同了,不要原路再一遍又一遍的走了,死胡同就是死胡同,再走多少遍都还是个死胡同!!
再这么下去,内心会崩溃的!!
所以,
继续看代码:看看能不能灵机一动:动了一下!!!
<?xml version="" encoding=""?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

//这里知道该mapper对应StudentMapper(dao)
<mapper namespace="com.learn.chapter4.mapper.StudentMapper">
    //这里知道mapper对应StudentBean(dao,bean,mapper三者紧密相连)
    //所以对于一mapper必须清楚的知道他对应的dao和bean是谁!!!
    <resultMap id="studentMap" type="com.learn.chapter4.po.StudentBean">
    //resultMap定义了mapper执行结果与StudentBean的映射规则
    //从这套规则里面能知道该bean的属性有哪些:
    //该bean对应的表是谁?
    //id,cnname,sex,note,studentSelfcard,studentLectureList
    //属性studentSelfcard是为这个bean添加的除了对应表的那些属性之外的一个属性
    //这个属性,是一个bean属性,实际上对应的是一个bean:StudentSelcardBean
    //StudentSelcardBean又是对应一个StudentSelcard表的
    //studentLectureList这个属性是一个bean集合属性,集合中的每个元素都对应一个studentLectureBean
    //studentLectureBean又是对应一个studentLecture表的
    //一个bean只能存放查询结果中的一条记录
    //先想bean:StudentBean
    //StudentBean不止对应一张表,到目前为止对应三张表
    //但是在这三张表中以Student为主表
    //现在要做到事情是,我要往StudentBean中填数据:只能通过对应的dao和mapper来完成查询和填写!!
    //任何bean的填写只能通过mapper来实现,而mapper必须通过dao来启动
    //mapper可以填写一个bean也可以填写一个bean集合
    //我的mapper可以轻松做到id,cnname,sex,note属性的填写
    //问题是,studentSelfcard属性和studentLectureList属性怎么填写呢?
    //这两个属性都是bean,也必须通过对应的mapper来完成填写,而mapper必须依赖对应的dao来启动
    //这里要建立映射规则
    //对studentSelfcard建立的映射规则是这样:
      1.使用本表的id作为参数去执行studentSelfcard表对应的dao然后执行对应的mapper
      2.从这次执行中获得的正确的记录只能有一条
      3.将这条记录的数据回填到studentSelfcard属性中(这件事是别的mapper做的哦)
        <id property="id" column="id"/>
        <result property="cnname" column="cnname"/>
        <result property="sex" column="sex" jdbcType="INTEGER"
                javaType="com.learn.chapter4.enums.SexEnum"
                typeHandler="com.learn.chapter4.typehandler.SexTypeHandler" />
        <result property="note" column="note"/>
        <association property="studentSelfcard" column="id"
                     select="com.learn.chapter4.mapper.StudentSelcardMapper.findStudentSelfcardByStudentId"/>
        <collection property="studentLectureList" column="id"
                    select="com.chapter4.mapper.StudentLectureMapper.findStudentLectureByStuId" />
        //这里看不出属性出来
        //这里就很明确了
        //根据我查询到的sex的值选择执行不同的resultMap
        //换句话说,如果按id在学生表中的查询结果里的sex是1就执行名为(id为)maleStudentMap的个resultMap
        <discriminator javaType="int" column="sex">
            <case value="1" resultMap="maleStudentMap"/>
            <case value="2" resultMap="femaleStudentMap">
        </discriminator>     
    </resultMap>

    <select id="getStudent" parameterType="int" resultMap="studentMap">
       SELECT id,cnname,sex,note
       FROM t_student
       WHERE id= #{id}
    </select>
  
    //这里分析这个resultMap
      对于一个resultMap必须清楚的知道要映射的bean是谁?MaleStudentBean
      这里让这个resultMap:maleStudentMap继承studentMap
      继承之后,会怎样?将拥有其所有特性么?
      继承不是等于拥有,而是需要的时候,如果没有可以问它要
    <resultMap id="maleStudentMap" type="com.learn.chapter4.po.MaleStudentBean"
               extends="studentMap">
        <association property="studentHealthMale"
                    select="com.learn.chapter4.mapper.StudentHealthMaleMapper.findStudentHealthMaleByStuId"
                    column="id"/>
        
    </resultMap>
    //这里有一个bean是MaleStudentBean
    //我们并没有针对这个bean写对应的mapper和dao
    //那怎么实现的回填呢?是通过在主表中建立的映射规则实现的
    //在主表中,如果通过主表的映射规则使用了鉴别器元素
    //那么在主表中,就可以定义两个其他的映射规则了
    //bean的回填不一定非得通过自己的mapper,但一定是通过mapper,通过mapper的映射规则
    //这里虽然是继承,与其说是继承,不如说是扩展,更加准确
    //又给studentMap增加一条映射规则
    <resultMap id="femaleStudentMap" type="com.learn.chapter4.po.FemaleStudentBean" extends="studentMap">
        <association property="studentHealthFemale" column="id"
                    select="com.learn.chapter4.mapper.StudentHealthFemaleMapper.findStudentHealthFemaleByStuId">
    </resultMap>
</mapper>
//最后的最后,我们来整理一下mapper的执行过程:
//我通过一个参数id(学生编号),调用学生表bean对应dao中的方法:getStudentById
//执行对应的sql得到四个数据,id,cnname,sex,note
//接下来要做什么事情了?:回填bean中的属性!!!
//怎么回填呢?
//那就是按照映射规则来一个一个的映射
//bean中的id属性怎么填呢?-->就取查询结果中的id吧
//bean中的cnname属性怎么填呢-->就取查询结果中的ccname吧
//bean中的sex属性怎么填呢?-->就取查询结果中的sex吧
//bean中的note属性怎么填呢?-->就取查询结果中的note吧
//bean中的studentSelfcard属性怎么填呢?
  这样,我们不是有id么,我们拿着这个id去执行一个dao方法,这个方法会做个查询,把结果这个结果逐一映射到一个bean中
  然后我们的属性就引用这个bean,就这么填,OK的,虽然填写的是一个地址值
//studentLectureList这玩意怎么填呢?
  还是一样的道理,我们不是有id么,那就把这个id作为参数,调用一个dao方法,dao方法会把结果映射到一bean集合中
  我们的属性就引用这个集合,这样就完成了填写,填写的是一个地址值

//那鉴别器代码是什么意思呢?
//你不是查出sex了么?这样,你看sex等于1还是2
  如果等于1,执行maleStudentMap映射规则
  如果等于2,就执行maleStudentMap这个映射规则

//假设等于1,这个规则将被执行,意味着要给MaleStudentBean的属性填入值
  而这个bean只有一个属性:studentHealthMale
  这个属性怎么填?
  首先,父亲映射里不是有了学生id,我们就用这个id,执行某dao中的方法,这里的映射规则里面是没有id的,就从父亲映射规则找
  找到后,把结果映射的到bean中,然后我们的属性引用这个bean
  这样一来,就填写完成了...

为什么这么绕?为什么这么乱呢?
怎么才能更加清楚到底怎么回事呢?
每天一遍,复杂和凌乱就怕重复,重复多了,再复杂也变简单了,再乱也顺了

猜你喜欢

转载自blog.csdn.net/weixin_42204641/article/details/81610157