(九)高级映射

目录


需求

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

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


一对一映射(使用 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 ;主要是看最后对映射结果的要求 ;

原文地址:https://www.cnblogs.com/young-youth/p/11665672.html