MyBatis学习:多表映射

目录

一、多表映射概念

1.1 多表查询结果映射思路

1.2 实体类设计方案

1.2.1 对一关系设计

1.2.2 对多关系设计

多表映射案例准备

二、对一映射

三、对多映射

四、多表映射总结

4.1 多表映射优化

4.2 总结:


一、多表映射概念

1.1 多表查询结果映射思路

数据库的表结构具有复杂性,不是所有数据库都达到第三范式或BCNF范式,故数据库查询结果与java对象的属性映射也变得复杂。MyBatis使用ResultMap实现复杂的数据库映射模式。示例如下:

这是一个需要映射的select语句:

<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

该语句具体思想如下:B对象标识一篇博客,由某位作者A编写P,每篇博文由很多评论C和标签PT、T。

我们需要设置ResultMap作为select标签的返回值类型,实现返回值的复杂映射。resultMap编写如下:

<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
  </collection>
</resultMap>

1.2 实体类设计方案

不同表格时间有一对一、一对多、多对多的多表关系。不同表格之间的实体类有不同的设计方案。

1.2.1 对一关系设计

外卖订单与用户是多对一关系。对一关系下,实体类中只要包含单个对方对象类型属性即可。属性中包含对方对象。

public class Customer {

  private Integer customerId;
  private String customerName;

}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系

}  

1.2.2 对多关系设计

用户与订单时一对多关系。对多关系下,实体类中只要包含对方类型集合属性即可。属性中包含对方对象集合。

public class Customer {

  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 体现的是对多的关系
}

public class Order {

  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系
  
}

//查询客户和客户对应的订单集合  不要管!

只有真实发生多表查询时,才需要设计和修改实体类,否则不提前设计和修改实体类!

无论多少张表联查,实体类设计都是两两考虑!

在查询映射的时候,只需要关注本次查询相关的属性!例如:查询订单和对应的客户,就不要关注客户中的订单集合!

多表映射案例准备

为后续继续学习多表映射关系,请先完成如下准备:

数据库:

CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) );

CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); 

INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');

INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 

实体类设计:

创建新的Module:mybatis-high-multitable-05

pojo包下创建:

@Data
public class Customer {

  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 体现的是对多的关系
  
}  

@Data
public class Order {
  private Integer orderId;
  private String orderName;
  private Customer customer;// 体现的是对一的关系
  
}  

二、对一映射

查询需求:根据orderId查询订单以及订单关联的用户的信息!

1. 配置Mapper接口并声明查询方法:

public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}

2. 实现Mapper映射文件:

<!-- 创建resultMap实现“对一”关联关系映射 -->
<!-- id属性:通常设置为这个resultMap所服务的那条SQL语句的id加上“ResultMap” -->
<!-- type属性:要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 -->
<resultMap id="selectOrderWithCustomerResultMap" type="order">

  <!-- 先设置Order自身属性和字段的对应关系 -->
  <id column="order_id" property="orderId"/>

  <result column="order_name" property="orderName"/>

  <!-- 使用association标签配置“对一”关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">

    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>

  </association>

</resultMap>

<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">

  SELECT order_id,order_name,c.customer_id,customer_name
  FROM t_order o
  LEFT JOIN t_customer c
  ON o.customer_id=c.customer_id
  WHERE o.order_id=#{orderId}

</select>

核心标签:

<assotiation>:配置对一关系的对象,将对一关系对象的属性赋值。

        property属性:对一对象在原对象中的属性名

        javaType属性:对一对象对应的java类名

        标签中声明对一对象的字段->属性对应关系

</association>

3. 注册Mapper映射文件

<!-- 注册Mapper配置文件:告诉Mybatis我们的Mapper配置文件的位置 -->
<mappers>

  <!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 -->
  <mapper resource="mappers/OrderMapper.xml"/>

</mappers>

三、对多映射

查询需求:根据customer_id查询客户和客户关联的订单信息!

1. 定义相关Mapper接口并声明方法

public interface CustomerMapper {

  Customer selectCustomerWithOrderList(Integer customerId);

}

2. 配置相关的Mapper映射文件

<!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 -->
<resultMap id="selectCustomerWithOrderListResultMap"

  type="customer">

  <!-- 映射Customer本身的属性 -->
  <id column="customer_id" property="customerId"/>

  <result column="customer_name" property="customerName"/>

  <!-- collection标签:映射“对多”的关联关系 -->
  <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">

    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>

    <result column="order_name" property="orderName"/>

  </collection>

</resultMap>

<!-- Customer selectCustomerWithOrderList(Integer customerId); -->
<select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
  SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
  FROM t_customer c
  LEFT JOIN t_order o
  ON c.customer_id=o.customer_id
  WHERE c.customer_id=#{customerId}
</select>

核心标签:

<collection>:配置对多对象,将对多对象的属性赋值

        property属性:对多对象在原对象中的属性名

        ofType:集合属性中元素的java类名

</collection>

3. 注册Mapper映射文件

<!-- 注册Mapper配置文件:告诉Mybatis我们的Mapper配置文件的位置 -->
<mappers>
  <!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 -->
  <mapper resource="mappers/OrderMapper.xml"/>
  <mapper resource="mappers/CustomerMapper.xml"/>
</mappers>

四、多表映射总结

4.1 多表映射优化

<setting name="autoMappingBehavior">标签:

指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。

进行多表resultMap映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的result标签!

举例:

<!--开启resultMap自动映射 -->
<setting name="autoMappingBehavior" value="FULL"/>
<resultMap id="teacherMap" type="teacher">
    <id property="tId" column="t_id" />
    <!-- 开启自动映射,并且开启驼峰式支持!可以省略 result!-->
<!--        <result property="tName" column="t_name" />-->
    <collection property="students" ofType="student" >
        <id property="sId" column="s_id" />
<!--            <result property="sName" column="s_name" />-->
    </collection>
</resultMap>

4.2 Mapper批量映射优化

多个Mapper需要映射时,在config文件中一个一个配置较为繁琐,MyBatis允许通过指定Mapper所在的包在指定Mapper映射文件。

创建要求:

Mapper接口和Mapper配置文件名必须保持一致,如:

        Mapper Interface:EmployeeMapper.java

        Mapper.xml:EmployeeMapper.xml

Mapper配置文件必须放在Mapper接口所在的包内:

1. 将Mapper配置文件和Mapper接口放在同一个package内,但是需要额外配置Maven打包方式,较为复杂

2. 在resources文件夹下创建于mapper接口package路径一致的文件目录结构来存放Mapper配置文件,如:

  •    Mapper接口放在com.landy.mapper包中
  •    在resources文件夹中创建com/landy/mapper文件路径,在mapper文件夹中存放相关的mapper.xml文件

随后,在config文件中配置相关包,即可编译成功:

    <!--  配置映射文件信息  -->
    <mappers>
        <package name="com.landy.mapper"/>
    </mappers>

4.3 总结:

对一:association + property(属性名) + javaType(返回实体类型)

对多:collection + property(属性名) + ofType(返回实体类型)

  • 50
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值