[04] 高级映射 association和collection

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

先看两张表,author 和 book:

  

业务上对应关系为,一个作者能写多本书,但是一本书只有一个作者。对应的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<Book> 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中可以这样写:

<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="price" column="price" />
        <!--关联属性-->
        <association property="author" javaType="dulk.learn.mybatis.pojo.Author">
            <!--注:此处column应为book中外键列名-->
            <id property="id" column="author_id" />
            <!--注:避免属性重名,否则属性值注入错误-->
            <result property="name" column="authorName" />
            <result property="age" column="authorAge" />
        </association>
    </resultMap>

    <!--嵌套查询,结果映射只能使用resultMap-->
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
        SELECT
            b.*,
            a.name AS ‘authorName‘,
            a.age  AS ‘authorAge‘
        FROM book b, author a
        WHERE b.author_id = a.id
        AND b.id = #{id}
    </select>

</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

            <!--注:此处column应为book中外键列名-->

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

    <!--嵌套查询,结果映射只能使用resultMap-->

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别名):

<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <!--author的resultMap-->
    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
        <id property="id" column="authorId"/>
        <result property="name" column="authorName"/>
        <result property="age" column="authorAge"/>
    </resultMap>

    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="price" column="price"/>
        <!--引用author的resultMap-->
        <association property="author" resultMap="authorResultMap" />
    </resultMap>

    <!--注意这里a.id的别名和authorResultMap中相对应-->
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
        SELECT
            b.*,
            a.id   AS ‘authorId‘,
            a.name AS ‘authorName‘,
            a.age  AS ‘authorAge‘
        FROM book b, author a
        WHERE b.author_id = a.id
        AND b.id = #{id}
    </select>
</mapper>

29

1

<mapper namespace="dulk.learn.mybatis.dao.BookDao">

2


3

    <!--author的resultMap-->

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

        <!--引用author的resultMap-->

15

        <association property="author" resultMap="authorResultMap" />

16

    </resultMap>

17


18

    <!--注意这里a.id的别名和authorResultMap中相对应-->

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也可以不用再联表。这种方式相当于两次查询,性能和效率较低,并不提倡。如上例使用这样的方式,则如下:

<mapper namespace="dulk.learn.mybatis.dao.BookDao">

    <resultMap id="bookResultMap" type="dulk.learn.mybatis.pojo.Book">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="price" column="price"/>
        <!--使用select属性进行查询关联-->
        <association property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>
    </resultMap>

    <!--简化了book的查询语句,不再需要与其他表关联-->
    <select id="findBookById" parameterType="long" resultMap="bookResultMap">
        SELECT b.*
        FROM book b
        WHERE b.id = #{id}
    </select>

    <!--新增了author表的查询语句,将会被调用获取结果并组装给book-->
    <select id="findAuthorById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Author">
        SELECT *
        FROM author
        WHERE id = #{id}
    </select>

</mapper>

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

        <!--使用select属性进行查询关联-->

8

        <association property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>

9

    </resultMap>

10


11

    <!--简化了book的查询语句,不再需要与其他表关联-->

12

    <select id="findBookById" parameterType="long" resultMap="bookResultMap">

13

        SELECT b.*

14

        FROM book b

15

        WHERE b.id = #{id}

16

    </select>

17


18

    <!--新增了author表的查询语句,将会被调用获取结果并组装给book-->

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<Book>:

<mapper namespace="dulk.learn.mybatis.dao.AuthorDao">

    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
        <id property="id" column="id"/>
        <result property="name" column="name" />
        <result property="age" column="age" />
        <!--使用collection属性,ofType为集合内元素的类型-->
        <collection property="bookList" ofType="dulk.learn.mybatis.pojo.Book" columnPrefix="book_">
            <id property="id" column="id"/>
            <result property="name" column="name" />
            <result property="price" column="price" />
        </collection>
    </resultMap>

    <select id="findById" parameterType="long" resultMap="authorResultMap">
        SELECT a.*, b.id AS ‘book_id‘, b.name AS ‘book_name‘, b.price AS ‘book_price‘
        FROM author a, book b
        WHERE a.id = b.author_id
        AND a.id = #{authorId}
    </select>

</mapper>

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

        <!--使用collection属性,ofType为集合内元素的类型-->

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

时间: 2024-08-29 05:17:37

[04] 高级映射 association和collection的相关文章

Mybatis学习记录(六)----Mybatis的高级映射

作者:余家小子 1.一对多查询 1.1 需求 查询订单及订单明细的信息. 1.2 sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关联即可. SELECT orders.*, USER.username, USER.sex, USER.address, orderdetail.id orderdetail_id, orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id FR

Mybatis深入了解(六)----关联查询(高级映射)

一对一查询 resultType resultMap 一对多查询 resultType resultMap 多对多查询 一对一查询 resultType resultType:使用resultType实现非常简单,如果POJO中没有包括查询的列名,可以新建扩展类继承父类,并在子类中添加列名对应的属性,即可完成映射. package cn.itcast.ssm.po; /** * 订单的扩展类 * @author Administrator * */ //通过此类映射订单和用户查询的结果,让此类继

mybatis入门基础(六)----高级映射(一对一,一对多,多对多)

一:订单商品数据模型 1.数据库执行脚本 创建数据库表代码: 1 CREATE TABLE items ( 2 id INT NOT NULL AUTO_INCREMENT, 3 itemsname VARCHAR(32) NOT NULL COMMENT '商品名称', 4 price FLOAT(10,1) NOT NULL COMMENT '商品定价', 5 detail TEXT COMMENT '商品描述', 6 pic VARCHAR(64) DEFAULT NULL COMMENT

Mybatis(四) 高级映射,一对一,一对多,多对多映射

天气甚好,怎能不学习? 一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种关系来讲,比如有员工和部门,一个部门中有多个员工,从部门方看,是一对多关系,而多名员工属于一个部门,是多对一关系,那么如果我们的业务需求只需要通过部门查找到所有的员工,那么我们就只需要进行单向一对多的映射,如果我们需要通过员工来查询出对应的部门,那么我们就需要进行单向多对一的映射,而如果我们这两个业

Mybatis学习总结(六)——高级映射(一对一,一对多,多对多)

一.订单商品数据模型 1.数据库执行脚本 创建数据库表代码: /*Table structure for table `t_user` */ CREATE TABLE t_user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(32) NOT NULL COMMENT '用户名称', birthday DATE DEFAULT NULL COMMENT '生日', sex CHAR(1) DEFAULT NULL COMMENT '性别',

MyBatis高级映射查询(3)

一.数据库数据和项目搭建过程 1.主要要四张表,分别为user用户信息表.items商品表.orderdetail订单明细表.orders订单表.表的结构和数据如下: 表结构 CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci CREATE TABLE `items` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(32) NOT NUL

六 mybatis高级映射(一对一,一对多,多对多)

1  订单商品数据模型 以订单商品数据为模型,来对mybaits高级关系映射进行学习. 1.1     数据模型分析思路 1.每张表记录的数据内容 分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程. 2.每张表重要的字段设置 非空字段.外键字段 3.数据库级别表与表之间的关系 外键关系 4.表与表之间的业务关系 在分析表与表之间的业务关系时一定要建立 在某个业务意义基础上去分析. 1.2     数据模型分析 用户表user: 记录了购买商品的用户信息 订单表:order

MyBatis入门第2天--高级映射与查询缓存

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.06.28 lutianfei none mybatis框架执行过程: 1.配置mybatis的配置文件,SqlMapConfig.xml(名称不固定) 2.通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂 SqlSessionFactory在实际使用时按单例方式. 3.通过SqlSessionFactory创建SqlSession SqlSession是一个面向用户接口(提供操

Mybatis学习笔记(三)—高级映射,延迟加载

本文主要介绍了如何使用resultMap完成高级映射:分析数据库中表之间的关系(一对一.一对多.多对多) 如何在mapper.xml文件中配置resultMap实现一对一.一对多.多对多:mybatis如何实现延迟加载 1       数据模型 数据库中有已经导入的四个表:items:(商品信息表):orderdetail:(订单明细表):orders:(订单表):user:(用户表) 1 CREATE TABLE items ( 2 id INT NOT NULL AUTO_INCREMENT