zoukankan      html  css  js  c++  java
  • (九)高级映射

    目录


    需求

    关联查询:查询购买某些商品的用户信息 ;

    主表:订单表 ;
    关联表:用户表 ;


    一对一映射(使用 resultType)

    1. sql 语句

      SELECT 
      `order`.* ,`user`.`name` ,`user`.sex
      FROM 
      `order`,`user`
      WHERE 
      `user`.id = `order`.user_id    ;
    2. 创建 pojo 对象

      将上面查询的结果列的所有信息,封装到该 pojo 中 ;这与 复杂查询 创建 pojo 对象不一样,复杂查询 创建 pojo 对象是为了,封装查询条件 ;这里我们是为了 封装查询结果

      从查询的列中,可以看出结果来自 userorder 表 ,我们在设计 pojo 对象的时候,选择让其继承包含列字段段多的类,这样,我们可以在 pojo 中少写一些属性;

      这里我选择继承字段多的 user 类 ;

      /**
      *User增强类,封装最后的查询结果
      *@author An
      */
      public class UserCustomerMapper extends User {
          // 将 order 类的字段添加进来
      
          private int order_id ;
          private int user_id ;
      
          public int getOrder_id() {
              return order_id;
          }
      
          public void setOrder_id(int order_id) {
              this.order_id = order_id;
          }
      
          public int getUser_id() {
              return user_id;
          }
      
          public void setUser_id(int user_id) {
              this.user_id = user_id;
          }
      }
    3. 创建映射关系文件

      <?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="xin.ijava.dao.UserCustomerMapper">
      
          <select id="findOrderUsers" resultType="xin.ijava.dao.UserCustomer">
              SELECT
                  `order`.* ,`user`.`name` ,`user`.sex
              FROM
                  `order`,`user`
              WHERE
                  `user`.id = `order`.user_id
          </select>
      </mapper>
      
    4. 创建同名的接口

      @SuppressWarnings("unused")
      public interface UserCustomerMapper {
          public List<UserCustomer> findOrderUsers() throws Exception ;
      }
    5. 测试结果

      这里写图片描述

    可以看到,我们已经将结果中列的数据,都封装到 UserCustomer 类中了 ;


    一对一映射(使用 resultMap)

    我们发现前面我们在创建 pojo 对象,是选择继承包含结果集中列多的类,然后在 pojo 类添加新的属性 ;

    我们发现,即使这样做,我们还是很反感,特别是不同表之间有重名的列,生成 get set 方法就会出问题, 为什么就不能直接添加一个包含那些属性的对象进去呢

    答案是可以的,使用 resultMap

    1. 创建 pojo 对象 ;

      public class UserOrders extends User {
      
          // 直接传进来 order 对象
      
          private Order order ;
      
          public Order getOrder() {
              return order;
          }
      
          public void setOrder(Order order) {
              this.order = order;
          }
      }
    2. 创建 resultMap

      <!--type :最后将结果映射到的对象类-->
      <resultMap id="findOrders" type="xin.ijava.dao.UserOrders">
          <!--主对象,也就是被继承对象-->
          <id column="id" property="id"></id>
          <result column="name" property="name"/>
          <result column="sex" property="sex"/>
      
          <!--关联对象,也就是传进来的对象-->
          <!-- property : 关联对象在主对象中的引用名-->
          <association property="order" javaType="xin.ijava.pojo.Order">
              <id column="order_id" property="order_id"/>
              <result column="user_id" property="user_id"/>
          </association>
      </resultMap>
    3. 配置 sql

      
      <sql id="query_Orders_users">
           SELECT
              `order`.* ,`user`.`name` ,`user`.sex
          FROM
              `order`,`user`
          WHERE
              `user`.id = `order`.user_id
      </sql>
      
      <select id="findOrdersUserResultMap" resultMap="findOrders">
          <include refid="query_Orders_users"/>
      </select>
      
    4. 创建接口方法

        public List<UserOrders> findOrdersUserResultMap() throws Exception ;
    5. 测试结果

      这里写图片描述

    可以看出来,结果也被我们封装进去了 ;


    小结

    可以看出,resultType 适用于将结果集中列的结果映射到对象的一次映射到对应的属性上(一对一 ) ;

    resultMap 则是用于,将结果中多列的内容,映射到一个对象中(一对多 ) ;

    resultType 无法实现延迟加载,resultMap 可以实现延迟加载 ;


    需求

    查询 订单订单明细


    一对多映射

    1. sql 语句查询

           SELECT
          `order`.order_id,
          `user`.id ,
          `user`.`name`  ,
          orderdetail.id orderDetailsId,
          orderdetail.number
          FROM `order`,`user`,
          orderdetail,items
          WHERE
          `user`.id = `order`.user_id
          AND
          orderdetail.item_id = items.id
          AND
          `order`.order_id = orderdetail.order_id ;

      查询结果:
      这里写图片描述
      备注:

      再进行多表查询的时候,分清主表,关联表(主表没有直接关联,就通过一系列的中间表进行关联)
      
      where 后面写主键关系,按照逻辑写下去;
      
    2. 创建 pojo 对象

      首先讲下 覆盖现象

      mybatis 在往对象中,映射结果的时候,一条记录一条记录的映射 ;

      这里说下,我们在映射文件中规定主对象的 iduserid,那么,mybatis 就会根据 userid ,来分辨是不是同一个对象 ,以便将信息映射到对象中;

      比如,第一条记录,创建出 pojo 对象了,然后 订单对象 被赋值了,然后映射第二条记录,mybatis 会去检查该条记录中的 userid ,看是不是新对象,如果是,则创建新的 pojo 对象,如果是已经创建过的对象,则将结果映射到之前的 pojo 对象中,这样,假如 pojo 字段,设定的不正确,就会产生 覆盖

      从结果中我们看到,张三 拥有多个不同的 订单号,因此,在 pojo 中,我们应该用集合存储 订单对象 ,来避免覆盖 ;

      订单明细,也是一个对象,一个订单会产生多条订单明细记录,因为一个订单会购买多种不同的产品嘛 ,因此,也用集合存储;

      public class UserOrders extends User {
      
          private List<OrderDetails> orderDetails ;
      
          private List<Order> orders ;
      
          public List<OrderDetails> getOrderDetails() {
              return orderDetails;
          }
      
          public void setOrderDetails(List<OrderDetails> orderDetails) {
              this.orderDetails = orderDetails;
          }
      
          public List<Order> getOrders() {
              return orders;
          }
      
          public void setOrders(List<Order> orders) {
              this.orders = orders;
          }
      }
    3. 创建 resultMap

      将结果信息封装到集合中,使用 collection

       <!--封装订单信息到 UsersOrder 中 -->
      <!--extends 继承其他 map -->
      <resultMap id="findOrdersAndOrderDetailsMap" type="xin.ijava.dao.UserOrders" extends="findOrders">
          <!--封装信息到 集合-->
          <!--ofType 封装对象的类型-->
          <!--property 封装对象的引用名字-->
          <collection property="orderDetails" ofType="xin.ijava.pojo.OrderDetails">
              <result column="orderDetailsId" property="order_id"/>
              <result column="number" property="number"/>
          </collection>
      </resultMap>
    4. 配置 sql

       <select id="findOrdersAndOrderDetails" resultMap="findOrdersAndOrderDetailsMap">
          SELECT
          `order`.order_id,
          `user`.id ,
          `user`.`name`  ,
          orderdetail.id orderDetailsId,
          orderdetail.number
          FROM `order`,`user`,
          orderdetail,items
          WHERE
          `user`.id = `order`.user_id
          AND
          orderdetail.item_id = items.id
          AND
          `order`.order_id = orderdetail.order_id
      </select>
    5. 编写接口方法

      public List<UserOrders> findOrdersAndOrderDetails() throws Exception ;
    6. 测试结果
      这里写图片描述

    我们可以发现,在数据库查询出来的 4 条记录,在这里被封装成 2 个对象了 ,完全符合我们的期望,因为,我们创建的 pojo 对象,是按照用户为主体的,上面的 4 条记录,是 2 个用户产生的,因此,最后也被封装到 2 个对象中 ;


    小结

    resultMap 主要是根据我们告诉它的 id ,也就是对象的唯一标识符号,来确定是不是同一个对象的 ;


    需求

    查询所有 用户 购买的具体商品,将它们封装到一个集合中 ;

    如果是:查询某一个具体 用户 购买的具体商品,将它们封装到一个集合中,这样打印账单的活,则没有必要使用 resultMap 了 ;

    主表: user

    关联表 :items


    多对多映射

    1. sql 语句

      SELECT 
      `user`.id user_id,
      `user`.`name` user_name,
      `user`.address user_address,
      `order`.order_id ,
      `order`.createtime create_time,
      items.id item_id,
      items.`name` item_name,
      orderdetail.number item_number
      FROM
      `user`,`order`,orderdetail,items
      WHERE
      `user`.id = `order`.user_id 
      AND
      `order`.order_id = orderdetail.order_id
      AND
      items.id = orderdetail.item_id ;
      
    2. 创建 resultMap

      <resultMap id="findUserAndItemsMap" type="xin.ijava.pojo.UserItems">
          <id column="user_id" property="id"/>
          <result column="user_name" property="name"/>
          <result column="user_address" property="address"/>
      
          <collection property="orders" ofType="xin.ijava.pojo.Order">
              <id column="order_id" property="order_id"/>
              <result column="create_time" property="createTime"/>
      
              <!--嵌套 collection -->
              <collection property="orderDetails" ofType="xin.ijava.pojo.OrderDetails">
                  <id column="order_id" property="order_id"/>
                  <result column="item_number" property="number"/>
                  <result column="item_number" property="number"/>
      
                  <!--关联对象-->
                  <association property="item" javaType="xin.ijava.pojo.Items">
                      <id column="item_id" property="id"/>
                      <result column="item_name" property="name"/>
                  </association>
              </collection>
          </collection>
      </resultMap>

      跟俄罗斯套娃一样,一层套一层,我们使用 collectionassociation 完成数据的嵌套 ;

    3. 配置 sql

      <select id="findUserAndItems" resultMap="findUserAndItemsMap">
          SELECT
              `user`.id user_id,
              `user`.`name` user_name,
              `user`.address user_address,
              `order`.order_id ,
              `order`.createtime create_time,
              items.id item_id,
              items.`name` item_name,
              orderdetail.number item_number
          FROM
              `user`,`order`,orderdetail,items
          WHERE
              `user`.id = `order`.user_id
          AND
              `order`.order_id = orderdetail.order_id
          AND
              items.id = orderdetail.item_id
      </select>
    4. 编写接口方法

      public List<UserItems> findUserAndItems() throws Exception ;
    5. 测试结果
      这里写图片描述


    总结

    选择 resultType 还是选择 resultMap 看需求 ;

    比如上面实现的商品明细,假如有特殊要求,将它们映射到一个集合中,那么则选用 resultMap ;如果只是想打印账单那样,那么使用 resultType ;主要是看最后对映射结果的要求 ;

  • 相关阅读:
    eval()用法
    TTL查看目标的操作系统
    Windows Mobile里用SQLite的 Pinvoke DLL "SQLite.Interop.DLL 异常处理
    创建56个民族的sql语句
    RSS 入门简介
    NAT 网络地址转换
    ARP 攻击
    Python核心数据类型——列表
    Python核心数据类型——字符串
    Linux下 PyDev + Eclipse安装方法
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665672.html
Copyright © 2011-2022 走看看