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

相關文章
相關標籤/搜索