[04] 高级映射 association和collection

之前我们提到的映射,都是简单的字段和对象属性一对一,假设对象的属性也是一个对象,即涉及到两个表的关联,此时应该如何进行映射处理?

先看两张表,author 和 book:
[04] 高级映射 association和collection_第1张图片   [04] 高级映射 association和collection_第2张图片

业务上对应关系为,一个作者能写多本书,但是一本书只有一个作者。对应的Java类如下:
public class Book {
    private long id;
    private String name;
    private int price;
    private Author author;

    //... getter and setter
}
8
 
1
public class Book {
              
2
    private long id;
3
    private String name;
4
    private int price;
5
    private Author author;
6
 
            
7
    //... getter and setter
8
}
public class Author {
    private long id;
    private String name;
    private int age;
    private List bookList;
    
    //... getter and setter
}
8
 
1
public class Author {
              
2
    private long id;
3
    private String name;
4
    private int age;
5
    private List<Book> bookList;
6
    
7
    //... getter and setter
8
}

1、association 关联

现在我们希望通过查询得到一个Book类,且该类中的author属性要求同时获取出来,这时候已经不是简单的数据库字段和对象属性的一对一映射,而涉及到两张表,此时我们就要用到 association 关键字。

association 表示一个复杂类型的关联,可以将许多结果包装成这种类型。它是 resultMap 中的标签属性,这意味着 当你需要使用嵌套查询返回结果,那么你的结果映射只能选择 resultMap,而不能再使用 resultType。

1.1 method1

使用起来和resultMap的基本结构无异,所以如上我们提到的查询需求,在mapper中可以这样写:


    
        
        
        
        
        
            
            
            
            
            
        
    

    
    
    
28
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2
 
            
3
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
4
        <id property="id" column="id" />
5
        <result property="name" column="name" />
6
        <result property="price" column="price" />
7
        
8
        <association property="author" javaType="dulk.learn.mybatis.pojo.Author">
9
            
10
            <id property="id" column="author_id" />
11
            
12
            <result property="name" column="authorName" />
13
            <result property="age" column="authorAge" />
14
        association>
15
    resultMap>
16
 
            
17
    
18
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
19
        SELECT
20
            b.*,
21
            a.name AS 'authorName',
22
            a.age  AS 'authorAge'
23
        FROM book b, author a
24
        WHERE b.author_id = a.id
25
        AND b.id = #{id}
26
    select>
27
    
28
mapper>

可以看到 association 最基本的两个属性:
  • property - 关联对象在类中的属性名(即Author在Book类中的属性名,author)
  • javaType - 关联对象的Java类型

而association中的结构,则和resultMap无异了,同样是id和result,但是仍然有两个需要注意的点:
  • id中的column属性,其值应该尽量使用外键列名,主要是对于重名的处理,避免映射错误
  • 同样的,对于result中的column属性的值,也要避免重名带来的映射错误,如上例若 a.name 不采用别名 "authorName",则会错误地将 b.name 赋值给Author的name属性

1.2 method2

之前有提到,说 association 中结构和resultMap无异,事实上我们也可以直接引用其他的resultMap,如下(注意修改id别名):


    
    
        
        
        
    

    
        
        
        
        
        
    

    
    
29
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2
 
            
3
    
4
    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
5
        <id property="id" column="authorId"/>
6
        <result property="name" column="authorName"/>
7
        <result property="age" column="authorAge"/>
8
    resultMap>
9
 
            
10
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
11
        <id property="id" column="id"/>
12
        <result property="name" column="name"/>
13
        <result property="price" column="price"/>
14
        
15
        <association property="author" resultMap="authorResultMap" />
16
    resultMap>
17
 
            
18
    
19
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
20
        SELECT
21
            b.*,
22
            a.id   AS 'authorId',
23
            a.name AS 'authorName',
24
            a.age  AS 'authorAge'
25
        FROM book b, author a
26
        WHERE b.author_id = a.id
27
        AND b.id = #{id}
28
    select>
29
mapper>

1.3 method3

最后,还有一种方式,就是我们先查询出author,再将其放到book中去,相当于查询语句分为两次,只是最终结果交给MyBatis来帮我们组装,这种方式利用了 association 的 select 属性,同时还需要另写 author 的查询sql,book 的查询sql也可以不用再联表。这种方式相当于两次查询,性能和效率较低,并不提倡。如上例使用这样的方式,则如下:


    
        
        
        
        
        
    

    
    

    
    

25
 
1
<mapper namespace="dulk.learn.mybatis.dao.BookDao">
2
 
            
3
    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
4
        <id property="id" column="id"/>
5
        <result property="name" column="name"/>
6
        <result property="price" column="price"/>
7
        
8
        <association property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>
9
    resultMap>
10
 
            
11
    
12
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
13
        SELECT b.*
14
        FROM book b
15
        WHERE b.id = #{id}
16
    select>
17
 
            
18
    
19
    <select id="findAuthorById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Author">
20
        SELECT *
21
        FROM author
22
        WHERE id = #{id}
23
    select>
24
 
            
25
mapper>

2、collection 集合

有了对 association 的认识,使用 collection 其实也就无非是依葫芦画瓢了,同样只能是 resultMap,同样需要注意列名重复的问题,同样可以引用resultMap或者使用select。下面索性直接看个例子吧,即获取一个Author作者,其中包含属性 List


    
        
        
        
        
        
            
            
            
        
    

    

22
 
1
<mapper namespace="dulk.learn.mybatis.dao.AuthorDao">
2
 
            
3
    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
4
        <id property="id" column="id"/>
5
        <result property="name" column="name" />
6
        <result property="age" column="age" />
7
        
8
        <collection property="bookList" ofType="dulk.learn.mybatis.pojo.Book" columnPrefix="book_">
9
            <id property="id" column="id"/>
10
            <result property="name" column="name" />
11
            <result property="price" column="price" />
12
        collection>
13
    resultMap>
14
 
            
15
    <select id="findById" parameterType="long" resultMap="authorResultMap">
16
        SELECT a.*, b.id AS 'book_id', b.name AS 'book_name', b.price AS 'book_price'
17
        FROM author a, book b
18
        WHERE a.id = b.author_id
19
        AND a.id = #{authorId}
20
    select>
21
 
            
22
mapper>

另外延伸一下关于避免字段重名的方式,如上例 select 中,列名的别名都增加了前缀 "book_",那么在collection中进行映射描时,就有两种方式:
  • 第一种即 column 的值和列名完全一致,如 column="book_id"
  • 第二种也就是推荐的方式,在 collection 中使用属性 columnPrefix 来定义统一前缀,在接下来的 column 中就可以减少工作量了,如上例中 columnPrefix = "book_",column = "id",它们的效果等同于 column = "book_id"


转载于:https://www.cnblogs.com/deng-cc/p/9337601.html

你可能感兴趣的:(java,数据库)