学会MyBatis中的级联

一、概述

MyBatis中的级联分为三种

  • 鉴别器(discriminator): 根据一些条件决定实现类级联的方案。比如体检表需要根据性别区分。
  • 一对一(association): 比如学生与学生证就是一对一的关系。
  • 一对多(collection): 比如班级与学生就是一对多的关系。

MyBatis中没有多对多的级联,一般使用两个一对多的级联代替。

二、了解resultMap元素的作用

resultMap定义的主要是一个结果集的映射关系,也就是SQL到Java Bean的映射关系定义,它也支持级联等特性。现版本的MyBatis只支持resusltMap查询,不支持更新或则保存。

resultMap元素的子元素

<resultMap>
   <constructor>
       <idArg/>
       <arg/>
   </constructor>
   <id />
   <result />
   <association />
   <collection />
   <discriminator>
       <case/>
   </discriminator>
</resultMap>
  • constructor:用于在实例化类时,注入结果到构造方法中

  • idArg:ID 参数;标记出作为 ID 的结果可以帮助提高整体性能

  • arg:将被注入到构造方法的一个普通结果

  • id:一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能

  • result:注入到字段或 JavaBean 属性的普通结果

  • association:一个复杂类型的关联。许多结果将包装成这种类型嵌套结果映射,关联可以指定为一个 resultMap 元素,或者引用一个

  • collection:一个复杂类型的集合。嵌套结果映射,集合可以指定为一个 resultMap 元素,或者引用一个

  • discriminator:使用结果值来决定使用哪个 resultMap

  • case:基于某些值的结果映射。嵌套结果映射一个 case 也是一个映射它本身的结果,因此可以包含很多相 同的元素,或者它可以参照一个外部的 resultMap。

三、案例

这里我们提供创建一个案例,创建了两个表customer表和invoice表,其中customer表和invoice表的关系是一对多。创建实体类时我们把invoice表中关于billing的信息提取出来创建一个BillingInfo实体类,其他的字段创建成一个实体类。这两个实体类之间的关系是一对一。注意阅读注释会有详细的解释

数据库

DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
  `customer_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(8) DEFAULT NULL,
  `last_name` varchar(8) DEFAULT NULL,
  `company` varchar(32) DEFAULT NULL,
  `address` varchar(64) DEFAULT NULL,
  `city` varchar(8) DEFAULT NULL,
  `state` varchar(8) DEFAULT NULL,
  `country` varchar(8) DEFAULT NULL,
  `postal_code` char(6) DEFAULT NULL,
  `phone` char(11) DEFAULT NULL,
  `fax` varchar(16) DEFAULT NULL,
  `email` varchar(16) DEFAULT NULL,
  `support_repld` varchar(4) DEFAULT NULL,
  PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `invoice`;
CREATE TABLE `invoice` (
  `invoice_id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_id` int(11) DEFAULT NULL,
  `invoice_date` datetime DEFAULT NULL,
  `billing_address` varchar(32) DEFAULT NULL,
  `billing_city` varchar(16) DEFAULT NULL,
  `billing_state` varchar(4) DEFAULT NULL,
  `billing_country` varchar(16) DEFAULT NULL,
  `billing_postalcode` varchar(8) DEFAULT NULL,
  `total` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`invoice_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

实体类

public class CustomerEntity {
    int customerId;
    String firstName;
    String lastName;
    String company;
    String address;
    String city;
    String state;
    String country;
    String postalCode;
    String phone;
    String fax;
    String email;
    String supportRepld;
	// 客户customer和发票invoice是一对多关系
    List<InvoiceEntity> invoiceEntityList= null;

	// ..省略get\set方法
}

public class BillingInfoEntity {
    int invoiceId;
    String billingAddress;
    String billingCity;
    String billingState;
    String billingCountry;
    String billingPostalCode;
	// ..省略get\set方法
}

public class InvoiceEntity {
    int invoiceId;
    Date invoiceDate;
    float total;
	
	// 发票invoice和账单billing是一对一关系
    BillingInfoEntity billingInfoEntity;
	
	// 发票invoice和客户customer是一对一关系 
    CustomerEntity customerEntity;

	// ..省略get\set方法
}

查询

这里我们对于resultMap使用级联采用了两种方式Nested ResultMapNested Select

接口

public interface SelectMapper {
	
	// Nested ResultMap方式定义的方法
	
    InvoiceEntity getInvoiceByInvoiceId(int id);

    InvoiceEntity getInvoiceForCustomerByInvoiceId(int id);

    CustomerEntity getCustomerById(int id);

	// Nested Select方式定义的方法
    CustomerEntity getCusById(int id);

    List<InvoiceEntity> getIncByCustomerId(int id);

    List<CustomerEntity> getAll();
}

映射器

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lzx.select.mappers.SelectMapper">

    <!-- Nested ResultSet(多用于多表连接查询,只需查询一次即可,但是语句复杂)-->
	
	<!--
		根据实体类InvoiceEntity中描述的关系创建一个新的结果集,association适用于一对一的关系。
		在这里,invoice里面的字段mybatis会自动帮我们映射,前提是你的数据库命名和字段的命名要符合规范
	-->
	<!--
		type属性为resultMap的映射的实体类,可以使用完全限定名,也可以使用别名
		autoMapping为是否启动自动映射,默认值是false,不启动
	 -->
    <resultMap id="invoiceAndBilling" type="InvoiceEntity" autoMapping="true">
		<!--association用于一对一级联,property是pojo中的属性。javaType是java这边的类型。 -->
        <association property="billingInfoEntity" javaType="BillingInfoEntity" autoMapping="true"/>
		<!--resultMap之间的相互引用-->
        <association property="customerEntity" resultMap="customerInfo"/>
    </resultMap>
    
	<!-- 
		根据实体类CustomerEntity中描述的关系创建一个新的结果集,collection适用于一对多的关系。
	-->
    <resultMap id="customerInfo" type="CustomerEntity" autoMapping="true">
    	<!--这里的ofType等同于association中的javaType-->    
		<collection property="invoiceEntityList" 
			resultMap="invoiceAndBilling" ofType="InvoiceEntity" />
    </resultMap>
	
    <select id="getInvoiceByInvoiceId" resultMap="invoiceAndBilling">
        select * from invoice where invoice_id = #{id}
    </select>

    <select id="getInvoiceForCustomerByInvoiceId" resultMap="invoiceAndBilling">
        select
        i.invoice_id,
        i.invoice_date,
        i.billing_address,
        i.billing_city,
        i.billing_state,
        i.billing_country,
        i.billing_postalCode,
        i.total,
        c.*
        from invoice i
        left join customer c
        on c.customer_id = i.invoice_id
        where i.invoice_id = #{id}
    </select>

    <select id="getCustomerById" resultMap="customerInfo">
      select *
      from invoice i
      left join customer c
      on c.customer_id = i.invoice_id
      where c.customer_id = #{id}
    </select>


    <!--Nested Select (也可用于多表连接查询,但是要查询多次,效率低,但是SQL语句简单)-->
    <resultMap id="invoiceAndCustomer" type="InvoiceEntity" autoMapping="true">
        <association property="billingInfoEntity" javaType="BillingInfoEntity" autoMapping="true"/>
		<!--select属性级联到customer的查询方法,column属性代表传入的参数-->
        <association property="customerEntity" column="customer_id"
                     select="com.lzx.select.mappers.SelectMapper.getCusById"/>
    </resultMap>

    <resultMap id="customerAndInvoice" type="CustomerEntity" autoMapping="true">
        <collection property="invoiceEntityList" column="customer_id"
                    select="com.lzx.select.mappers.SelectMapper.getIncByCustomerId"/>
    </resultMap>



    <select id="getIncByCustomerId" resultMap="invoiceAndCustomer" >
        select * from invoice where customer_id = #{id}
    </select>

    <select id="getCusById" resultMap="customerAndInvoice">
        select * from customer where customer_id = #{id}
    </select>

    <select id="getAll" resultType="com.lzx.select.entity.CustomerEntity">
        select * from customer
    </select>	    
</mapper>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值