Mybatis学习(2)—— 对象关系映射

【场景】在实际开发中,实体类之间有一对1、一对多、多对多的关系,因此须要正确配置它们对应关系,Mybatis经过配置文件可以从数据库中获取列数据后自动封装成对象。html

1. 一对一映射

以每一个学生有一个地址为例:java

public class Address
    {
        private Integer addrId;
        private String street;
        private String city;
        private String state;
        private String zip;
        private String country;
        // setters & getters
    }sql

public class Student
    {
        private Integer studId;
        private String name;
        private String email;
        private PhoneNumber phone;
        private Address address;
        //setters & getters
    }数据库

须要在对应的maper.xml文件里定义它们的映射关系。经常使用的几种方式以下: app

1.1 继承ResultMap,使用 . 表示嵌套对象的引用

这种方式就是定义一个继承自Student类型的ResultMap,而后将对应须要包含的address信息给映射进去。原有Student的映射定义以下:性能

<resultMap type="Student" id="StudentResult">  spa

    <id  property="studId" column="stud_id"/>  xml

    <result property="name" column="name" />  htm

    <result property="email" column="email"/>  对象

    <result property="phone" column="phone"/>  

</resultMap>  

继承Student的定义以下:

<resultMap type="Student" id="StudentWithAddressExtResult" extends="StudentResult">  

    <result property="address.addrId" column="addr_id"/>  

    <result property="address.street" column="street"/>  

    <result property="address.city" column="city"/>  

    <result property="address.state" column="state"/>  

    <result property="address.zip" column="zip"/>  

    <result property="address.country" column="country"/>  

</resultMap>  

至关于把address的对应属性和表里的字段映射给单独定义在一个地方映射起来。查找语句能够根据以下定义:

<select id="selectStudentWithAddress" parameterType="int" resultMap="StudentWithAddressExtResult">  

    select stud_id, name, email,phone, a.addr_id, street, city, state, zip, country  

    FROM STUDENTS s left outer join ADDRESSES a on s.addr_id=a.addr_id  

    where stud_id=#{studId}  

</select>  

对应的mapper接口定义以下:

public interface StudentMapper {  

    Student selectStudentWithAddress(int id);  

}  

StudentService里定义相关的方法以下:

public Student findStudentWithAddressById(int id) {  

    SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();  

    try {  

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);  

        return studentMapper.selectStudentWithAddress(id);  

    } finally {  

        sqlSession.close();  

    }  

}  

验证:

public static void main( String[] args ) {  

        StudentService studService = new StudentService();  

        Student student1 = studService.findStudentWithAddressById(1);  

        System.out.println(student1);  

}  

输出结果:

Student [studId=1, name=Timothy, email=timothy@gmail.com, phone=123-123-1234, address=Address [addrId=3, street=710 N Cable Rd, city=Lima, state=OH, zip=45825, country=Allen]]  

在一些状况下,咱们已经定义了Address的映射ResultMap,若是再在这里从新定义一遍,就显得比较冗余了。

1.2 association直接关联

若是咱们已经定义好了Address的映射,假设它的定义以下:

<mapper namespace="com.yunzero.map.mappers.AddressMapper">        

    <resultMap type="Address" id="AddressResult">  

        <id property="addrId" column="addr_id"/>  

        <result property="street" column="street"/>  

        <result property="city" column="city"/>  

        <result property="state" column="state"/>  

        <result property="zip" column="zip"/>  

        <result property="country" column="country"/>  

    </resultMap>  

    <select id="selectAddressById" parameterType="int" resultMap="AddressResult">  

        select * from ADDRESSES where addr_id=#{addrId}  

    </select>  

</mapper>  

对应的Student ResultMap就须要修改以下:

<resultMap type="Student" id="StudentWithAddressResult">  

        <id property="studId" column="stud_id"/>  

        <result property="name" column="name"/>  

        <result property="email" column="email"/>  

        <result property="phone" column="phone"/>  

        <association property="address" resultMap="com.yunzero.map.mappers.AddressMapper.AddressResult"/>  

</resultMap>  

定义了一个association的属性,而后将对应的resultMap指向对应的AddressResult。这里定义的AddressResult是定义在另一个文件以及命名空间里,因此须要引用它的全名。

1.3 内嵌select关联

<resultMap type="Student" id="StudentWithAddressNestedSelect">  

    <id  property="studId" column="stud_id"/>  

    <result property="name" column="name"/>  

    <result property="email" column="email"/>  

    <result property="phone" column="phone"/>  

    <association property="address" column="addr_id" select="com.yunzero.map.mappers.AddressMapper.selectAddressById"/>  

</resultMap>  

在association里指定column字段,它做为嵌入select语句里对应的参数。

1.4 ResultMap嵌套

<resultMap type="Student" id="StudentWithAddressNestedResultMap">  

    <id  property="studId" column="stud_id"/>  

    <result property="name" column="name"/>  

    <result property="email" column="email"/>  

    <association property="address" javaType="Address">  

        <id property="addrId" column="addr_id"/>  

        <result property="street" column="street"/>  

        <result property="city" column="city"/>  

        <result property="state" column="state"/>  

        <result property="zip" column="zip"/>  

        <result property="country" column="country"/>  

    </association>  

</resultMap>  

2. 一对多映射

以一个教师有多门课程为例:

public class Course

    {

        private Integer courseId;

        private String name;

        private String description;

        private Date startDate;

        private Date endDate;

        private Integer tutorId;

        //setters & getters

    }

public class Tutor

    {

        private Integer tutorId;

        private String name;

        private String email;

        private Address address;

        private List<Course> courses;

        // setters & getters

    }

须要在对应的maper.xml文件里定义它们的映射关系。经常使用的几种方式以下: 

2.1 嵌入ResultMap

关于课程的配置以下:

<mapper namespace="com.yunzero.map.mappers.CourseMapper">  

    <resultMap type="Course" id="CourseResult">  

        <id  column="course_id" property="courseId"/>  

        <result column="name" property="name"/>  

        <result column="description" property="description"/>  

        <result column="start_date" property="startDate"/>  

        <result column="end_date" property="endDate"/>  

    </resultMap>      

    <select id="selectCoursesByTutor" parameterType="int" resultMap="CourseResult">  

        select * from COURSES where tutor_id=#{tutorId}  

    </select>        

</mapper>  

关于教师的配置以下:

<resultMap type="Tutor" id="TutorWithCoursesNestedResult">  

    <id  column="tutor_id" property="tutorId"/>  

    <result column="tutor_name" property="name"/>  

    <result column="email" property="email"/>  

    <association property="address" resultMap="com.yunzero.map.mappers.AddressMapper.AddressResult"/>  

    <collection property="courses"  resultMap="com.yunzero.map.mappers.CourseMapper.CourseResult"  />  

</resultMap>  

对于多个course,它须要使用collection属性,并指定对应的CourseResult。 

对应的查询语句以下:

<select id="selectTutorById" parameterType="int" resultMap="TutorWithCoursesNestedResult">  

    SELECT t.tutor_id, t.name as tutor_name, email, a.addr_id, street, city, state, zip, country,  

    course_id, c.name, description, start_date, end_date  

    FROM TUTORS t left outer join ADDRESSES a on t.addr_id=a.addr_id  

    left outer join COURSES c on t.tutor_id=c.tutor_id  

    where t.tutor_id=#{tutorId}  

</select>  

对应的mapper接口和TutorService的实现以下:

public interface TutorMapper {        

    Tutor selectTutorById(int tutorId);  

}  

public Tutor findTutorById(int tutorId) {  

    SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();  

    try {  

        TutorMapper mapper = sqlSession.getMapper(TutorMapper.class);  

        return mapper.selectTutorById(tutorId);  

    }             

    finally {  

        sqlSession.close();  

    }  

}  

2.2 嵌入select

<resultMap type="Tutor" id="TutorWithCoursesNestedSelect">  

    <id  column="tutor_id" property="tutorId"/>  

    <result column="tutor_name" property="name"/>  

    <result column="email" property="email"/>  

    <association property="address" resultMap="com.yunzero.map.mappers.AddressMapper.AddressResult"/>  

    <collection property="courses"  column="tutor_id" select="com.yunzero.map.mappers.CourseMapper.selectCoursesByTutor"/>  

 </resultMap>  

<select id="selectTutorWithCourses" parameterType="int" resultMap="TutorWithCoursesNestedSelect">  

    SELECT t.tutor_id, t.name as tutor_name, email, a.addr_id, street, city, state, zip, country  

    FROM TUTORS t left outer join ADDRESSES a on t.addr_id=a.addr_id  

    where t.tutor_id=#{tutorId}  

</select>  

 这种方式和前面那种方式的差异在于它将查找对应course的方法委派给对应course的映射定义里,因此这里值须要考虑它和address的映射就能够了。而前面经过两个链接操做至关于将全部结果都返回来了,就不须要再去利用别的查询。固然,由于是一对多的映射牵涉到返回多个结果,这种方式可能须要执行屡次查询,有可能致使性能的问题。

参考:

https://www.cnblogs.com/zhaopengcheng/p/7094880.html

http://shmilyaw-hotmail-com.iteye.com/blog/2357862

相关文章
相关标签/搜索