结果集映射,顾名思义跟结果集有关。无非就是把SQL的查询结果映射到JavaBean的字段上。
一。字段映射
比如有张数据表结构如下:
在后台的JavaBean中,如果遵守规范的话,属性名和列名一致,那么我们就不需要手动做字段映射,MyBatis会自动帮我们把值填充到Bean中。但现在情况不一样,Bean的属性名和数据库列名对应不上。
import java.util.ArrayList;
import java.util.List;
public class Grade {
private String gradeId; // 班级ID
private String gName; // 班级名
private List<Student> stuList = new ArrayList<Student>(); // 班级中的学生
public String getGradeId() {
return gradeId;
}
public void setGradeId(String gradeId) {
this.gradeId = gradeId;
}
public String getgName() {
return gName;
}
public void setgName(String gName) {
this.gName = gName;
}
public List<Student> getStuList() {
return stuList;
}
public void setStuList(List<Student> stuList) {
this.stuList = stuList;
}
@Override
public String toString() {
return "Grade [gradeId=" + gradeId + ", gName=" + gName + ", stuList="
+ stuList + "]";
}
}
gradeId和GID明显对应不上,但是修改列或者属性名是不可取的,原因不多说。我们可以通过MyBatis的字段映射在不修改代码的情况下完成这个需求,给它俩建立一种映射关系:
字段映射,当数据库的列名和类的属性名不一致时,需要通过建立映射关系使得它俩对应上。
返回的结果都是grade(自己取的typeAliases),只是多了一层映射关系。
<resultMap type="grade" id="mappingGid">
<!-- 主键列用id标签 -->
<id property="gradeId" column="GID"/>
<!--
非主键就用result:
<result property="gName" column="gname"/> -
->
</resultMap>
<select id="queryAll" resultType="grade" resultMap="mappingGid">
select * from grade
</select>
restltMap属性指向上边定义的resultMap的id即可。resultMap标签还有个autoMapping属性,意思是自动映射,默认值是true,改成false的话就要手动指定需要建立映射关系的列以及属性了。
二。多对一(
many to
one) 映射
表关系:
![](https://img-blog.csdn.net/20180117204745854?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYzMTEzNzI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
grade表:GID、GNAME
student表:SID、SNAME、GID
GID是关联grade表的外键。
多对一的视角:student --> grade。多个学生对应一个grade,一个学生只能有一个grade。
在设计Bean的时候,应该是这样的:
public class Student {
private String sId;
private String sName;
private Grade grade;
public String getsId() {
return sId;
}
public void setsId(String sId) {
this.sId = sId;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Student [sId=" + sId + ", sName=" + sName + ", grade=" + grade
+ "]";
}
}
包含一个grade属性,在查询到学生信息的同时把对应的班级查出来并填充进去。当然用Java代码编写逻辑也是完全能够实现的,但是有了MyBatis的结果集映射,我们并不需要编写这样的逻辑。确定好是一对多关系后,在映射文件中声明映射关系。下面就把这个例子的代码都贴上来吧:
Student映射接口:
import java.util.List; import cn.et.lesson03.entity.Student; public interface StudentMapper {
<!-- 映射多对一关系 --> <resultMap type="student" id="mappingGrade"> <association property="grade" column="gid" select="cn.et.lesson03.xml.GradeMapper.queryGradeByGid"></association> </resultMap>
/* 根据ID查询学生 */ public Student queryStuById(String sId); /*根据班级ID查询学生*/ public List<Student> queryStusByGId(String gId);}
现在要调用
queryStuById
,返回一个student的同时,把这个student的grade属性填充进去,也就是说还需要一个 select * from grade where gid = x 这么一条SQL语句,定义在grade类对应的映射文件中:
<select id="queryGradeByGid" resultType="grade">
select * from grade where GID = #{gid}
</select>
然后在Student类的映射文件中建立映射关系:
<!-- 映射多对一关系 -->
<resultMap type="student" id="mappingGrade">
<association property="grade" column="gid" select="cn.et.lesson03.xml.GradeMapper.queryGradeByGid"></association>
</resultMap>
type = 查询返回结果
id = 映射命名
association = 声明是多对一映射。
property
=
"grade" 需要填充的属性
column
=
"gid" 外键列
select
=
获取对应的grade数据行的
SQL语句,上上边那个,语法格式:命名空间.声明。
映射接口中方法的SQL语句:
<select id="queryStuById" resultType="student" resultMap="mappingGrade">
select * from student where SID = #{0}
</select>
测试方法:
@Test
public void mappingGrade() throws IOException{
SqlSession session = getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.queryStuById("1");
System.out.println(student.getGrade());
}
结果:
流程:
调用方法 --> 执行接口映射方法之前先执行resultMap -->
通过association中的column外键,执行
association
对应的SQL语句获取结果集,填充到
property --> resultMap结束 --> 执行方法对应的SQL语句返回最终结果。
三。一对多映射(one to
many
)
一对多映射很简单,一个班级对应多个学生,查询一个班级的同时获取班级中的所有学生,填充到stuList属性中:
把上面的例子反过来想就OK了。班级和学生在数据库中的关系是主外键关联,通过grade表的主键到student表查询,需要一个这个的语句:select * from student where GID = #{gid}。
这个语句在Student的映射文件中定义:
<select id="queryStusByGId" resultType="student">
select * from student where GID = #{gid}
</select>
<resultMap type="grade" id="mappingStuList">
<collection property="stuList" javaType="arraylist" column="gid" select="cn.et.lesson03.xml.StudentMapper.queryStusByGId"></collection>
</resultMap>
一对多关系用collection表示。
property = 要填充的属性
javaType = 该属性的数据类型
column = 主键,studen表的外键
select = student映射文件中的语句:
select * from student where GID = #{gid}
测试方法:
@Testpublic void queryStu() throws IOException {
SqlSession session = getSession();
GradeMapper mapper = session.getMapper(GradeMapper.class);
Grade grade = mapper.queryGradeById("1");
List<Student> list = grade.getStuList();
for (Student student : list) {
System.out.println(student.getsId() + "---" + student.getsName());
}
}
运行结果:
四。基于注解实现的结果集映射
字段映射:
@Results({
@Result(column="SID" , property = "stuId" , id = true)})
@Select("select * from student where sid = #{sId}")
public Student queryStuById(String sId);
多对一映射:
@Results({
@Result(column = "SID", property = "stuId", id = true),
@Result(property = "grade", column = "GID",
one = @One(select = "cn.et.lesson03.anno.GradeMapper.queryGradeById")) })
@Select("select * from student where sid = #{sId}")
public Student queryStuById(@Param("sId") String sId);
one表示多对一映射,多个学生属于一个grade,指向的方法也是一个grade:
@Select("select * from grade where GID = #{0}")
public Grade queryGradeById(String gId);
一对多映射:
指向的方法返回值是个list,所以还要在映射声明中指定一下javaType。
@Results({
@Result(column = "GID", property = "stuList", javaType = ArrayList.class,
many = @Many(select = "cn.et.lesson03.anno.StudentMapper.queryStusByGId")) })
@Select("select * from grade where GID = #{0}")
public Grade queryGradeById(String gId);
一对多用many表示,因为查询结果是多条,指向方法:
@Results({
@Result(column = "SID" , property = "stuId")})
@Select("select * from student where GID = #{param1}")
public List<Student> queryStusByGId(String gId);