ResultMap 、一对多、多对一
ResultMap
当数据库的字段名和Java中实体类的属性名不一致时,比如:
这个时候Mybatis自动映射就会失败,比如:
结果为:
这是因为,
select * from user where id = #{id}
等价于
select id,name,pwd from user where id = #{id}
mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 去对应的实体类中查找相应列名的get/set方法 , 也就是说,查询出一行记录后,Mybatis会new一个User对象,然后调用setId()、setName()和setPwd()方法为user对象赋值,然后返回这个对象。但是,由于实体类User中并没有getPwd()方法 , 所以password返回null 。
解决方法:
- 为列名指定别名 , 别名和java实体类的属性名一致。
<select id="selectUserById" resultType="User">
select id , name , pwd as password from user where id = #{id}
</select>
- 使用结果集映射:
ResultMap【推荐】
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
多对一
多对一最经典的例子就是:学生和老师的关系,对于学生而言,多个学生对应同一个老师。数据库中的表结构如下:
创建数据表
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
创建实体类
public class Student {
private int id;
private String name;
private Teacher teacher;
}
public class Teacher {
private int id;
private String name;
}
编写Mapper方法
public interface StudentMapper {
public List<Student> getStudents();
}
编写mapper.xml文件
- 方法一:
按查询嵌套处理- 做一个结果集映射:StudentTeacher
- StudentTeacher结果集的类型type为 Student
- Student>Teacher对应多对一,association标签中的property对应Student实体类【多】的属性名,column对应数据库中列名,传给下一个sql的字段名,javaType为下一个sql【一】的返回类型,select为下一个sql语句的id。
<mapper namespace="com.yuan.mapper.StudentMapper">
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="com.yuan.domain.Student">
<association property="teacher" column="tid" javaType="com.yuan.domain.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.yuan.domain.Teacher">
select * from teacher where id = #{id}
</select>
</mapper>
- 如果要传递多个字段到下一个sql语句时,格式为column="{key=value,key=value}",key是传给下个sql的取值名称,value是当前sql查询的字段名。比如:
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="{id=tid,name=tid}" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id} and name = #{name}
</select>
- 方法二:
按结果嵌套处理:直接查询出结果,进行结果集的映射
<!--
按查询结果嵌套处理
思路:
1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
编写测试类
public class MybatisTest {
@Test
public void testGetStudents(){
SqlSession session = MyBatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudents();
}
}
}
一对多
和上面的例子一样,一对多就是从老师的角度来看,一个老师拥有多个学生。
实体类:
public class Student {
private int id;
private String name;
private int tid;
}
public class Teacher {
private int id;
private String name;
//一个老师多个学生
private List<Student> students;
}
sql语句:
方法一:按查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<!--column是一对多的外键 , 写的是一的主键的列名-->
<collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
方法二:按结果嵌套处理
<mapper namespace="com.kuang.mapper.TeacherMapper">
<!--
思路:
1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
2. 对查询出来的操作做结果集映射
1. 集合的话,使用collection!
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
-->
<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>
</mapper>
总结
- 注意属性名和字段不一致的问题
- 多对一 用 关联-association
- 一对多 用 集合-collection
- JavaType和ofType都是用来指定对象类型的,JavaType是用来指定pojo中属性的类型,ofType指定的是映射到list集合属性中pojo的类型。
参考链接:https://mp.weixin.qq.com/s/Dpt0LHTgx0kL7RCk8PZ2aw
版权声明:本文为qq_36895015原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。