Result Map的复杂使用
ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
那么什么是一种描述呢?
这里有两张表,其中一张是学生,另一张是老师,那么这里的关系就是:
站在学生角度上:多个学生对应一个老师(多对一)
站在老师角度上:一个老师对应多个学生(一对多)
多对一深入理解1:
首先我们先分析一下实体类,
通过实体类,我们可以确定我们查询的目标其实就是 id,name ,teacher三样东西,
但是我们再来分析数据库中的表,我们发现,数据库中,关于student这张表,其实只有id,name,tid
这三个字段,那么但我使用:
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
这句话的,我的返回的结果其实就是id,name,tid,对应数据库中的三个字段
那么问题来了teacher没了,因为
tid != teacher
这就是典型的查询时数据库字段名和实体类属性名不一致的问题
既然如此,那么我们就可以利用ResultMap来解决!
为啥呢? 还记得一开始其实就说过的ResultMap的思想就是来映射数据库字段和实体类属性名的,之前我们可以简单的利用这个功能来简单的做到类似于别名
的功能,这里的情况无非就是复杂了一点,变成了一个对象而已。
好了,那么我们开始写ResultMap的映射:
<resultMap id="StudentTeacher" type="Student">
<association property="teacher" column="tid"
javaType="Teacher" select="getTeacher"/>
</resultMap>
类似于别名操作,这里也是一个数据库字段名对应一个实体类属性名
property:实体类属性名
column:数据库字段名
当然由于teacher是一个对象,我们不能简单的做到直接映射,这里的javaType其实就是指定这个Teacher对象的对应的实体类
好了,下一步怎么办的呢?这个时候我们就会在想我们想要查询的时teacher这个对象,但是teacher这个对象其实存在于数据库中teacher这个表中,因此顺理成章,我们需要调用teacher这张表的查询语句,也就是
最后一个属性 :select=“getTeacher”
这个属性当然不是凭空产生的,我们是调用了另一个select语句
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
我们通过调用这个语句,来获得我们所需要的teacher对象,那么我们传入的条件是什么呢?
其实就是tid ,但是由于传入的只是一个属性,where id = #{id}中id不管写啥都是对,这个是Mybatis的一个特性
写道这里,相比你也明白了,这里的逻辑就类似SQL中子查询。
话说回来,我们再来想一个问题,我们为啥要写这么复杂的查询的语句呢?其实仔细想想,我们在设计数据库考虑到数据库设计的三大范式,我们经常需要的数据分布在多个表中,并通过一定的连接点进行连接,这当然是好的,但是当我们在设计实体类时,就不能这样了,我们需要获得时对应的信息(teacher)而不是一个连接点(tid)
这时候我们就需要ResultMap来进行一一映射,来保证我们的查询结果
多对一深入理解2:
你以为到这里就结束了吗?
对于多对一查询,我们还有另一种方法
同样我们先来看select语句
select s.id sid, s.name sname, t.name tname
from student s,teacher t
where s.tid = t.id
和刚才的那么sql语句不同,这里使用了联表查询,由于使用别名操作,我们的结果也不同,
有sid,sname,tname;
不信?我们查查数据库
同样这三个字段名和我们实体类的属性名不同,那么这里就很顺理成章的要使用ResultMap来进行映射了
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
id——》sid
name——》sname
这两个都简单,不需要说明了,就是简单的映射
那么
teacher——》?
teacher 是一个复杂对象,我们要拆开再映射,我们把teacher拆开有个name(只需要name一个属性哦!)
name——》tname
至此为止,所有的属性都对应上了,那么映射也就完成了
综上所述:上述两个方法,各有优势,一个sql好写,一个xml好写,各取所需
还是那句话 :方法本身不重要,重要的是理解
我觉得只要有个映射的思想,慢慢的写,我们都能写出来
一对多深入理解1:
你又以为结束了?
我还没讲一对多呢!
这次我们站在老师角度,我们想要查询一个老师下所有的学生
其实思路是类似的,这次我们先不看代码,先分析。
我们的目标是:name List students
同样我们先使用第一种方法:
我们能查到啥:id name
没错这次我们从老师角度出发查询只能查到id和name
那么List students !=id
莫得,于是我们要进行映射!来上代码!
这里我们只要分析collection里的东西,colletion叫住集合,是用来映射一个集合对象。
同样:property:实体类属性名 javaType:该属性的类名 ofType :该集合的泛型
colume:id
同样类似于一对多,我们利用一个select语句 ,用id作为条件,来获取我们的所需要的集合对象
很简单,有木有!
一对多深入理解2:
来来来,最后一个了
看到这里,这个映射的概念想必以及十分的熟悉了
第二种一对多的方法:写好复杂的联表查询的SQL,然后一一映射,这里我就不做赘述了
直接上代码
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
我们首先在SQL语句中,查出了啥?
sid
sname
tname
tid
那么我们来一一对应
name ——》tname
Liststudents ——》 ?
这里同样我们再拆,一个student拆成 id name tid三个东西再来一一对应
id——》sid
name——》sname
tid——》tid
这里在注意一点,这里我们只需要写ofType=“student”
好了,完成收工,2个小时2000字左右,望各位学有所成