MyBatis关系映射

概述+数据模型

Mybatis关系映射主要是包括一对一,一对多,多对一,和多对多关系。
再进行我们关系映射的时候,我们需要有一个数据模型来模拟我们对应的相应关系,我们采用的数据模型为用户和订单,订单和订单明细,以及商品之间的关系。

数据库表:

用户表user:记录了购买商品的用户信息。
订单表orders:记录了用户所创建的订单(购买商品的订单)。
订单明细表orderdetail:记录了订单的详细信息即购买商品的信息。
商品表items:记录商品信息。

数据模型图:

这里写图片描述

数据表之间的关系:

先分析数据级别之间有关系的表之间的业务关系:

usre和orders:
user —-> orders:一个用户可以创建多个订单,一对多
orders —-> user:一个订单只由一个用户创建,一对一

orders和orderdetail:
orders —-> orderdetail:一个订单可以包括 多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系。
orderdetail —-> orders:一个订单明细只能包括在一个订单中,一对一

orderdetail和itesm:
orderdetail —-> itesms:一个订单明细只对应一个商品信息,一对一
items —-> orderdetail:一个商品可以包括在多个订单明细 ,一对多

再分析数据库级别没有关系的表之间是否有业务关系:
orders和items:
orders和items之间可以通过orderdetail表建立 关系。

一对一查询

实例:查询订单信息,关联查询创建订单的用户信息。
SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE orders.user_id = user.id

主查询表:orders
关联查询表:user
联结查询:内联结

利用ResultType

1、SQL语句的书写要领:先确定查询的主表,在确定查询的关联表,关联查询是使用内联结还是外联结。
2、POVO扩展类创建。(这是由于关联查询出来的信息是多张表的综合字段,所以我们可以根据POJO创建我们的扩展类)
3、Mapper.xml和Mapper.java的代理编写
4、进行测试

相关代码:

//  POJO基础类
    public class Orders {
        private int id;
        private int userid;
    //  private int user_id;

        private String number;
        private Date createtime;
        private String note;
    }

// POVO扩展类   Orders的扩展类,通过此类可以映射订单和用户查询的结果。
    public class OrdersExtends  extends Orders{
        private String username;
        private String sex;
        private String address;
    }

// Mapper.xml配置
    <select id="findorderanduser" resultType="com.wf.model.OrdersExtends">
        SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE     orders.user_id = user.id
    </select>

//Mapper.java 代理接口
    public interface OrdersExtendsMapper {
        public List<OrdersExtends> findorderanduser();
    } 

//测试代码
        @Test
    public void testOrdersExtendsMapper() {

        SqlSession session = sqlsessionfactory.openSession();
        OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
        List<OrdersExtends> list = orderextendsmapper.findorderanduser();
        for(OrdersExtends o :list){             System.out.println(o.getId()+":"+o.getUserid()+":"+o.getUsername()+":"+o.getAddress());

//System.out.println(o.getId()+":"+o.getUser_id()+":"+o.getUsername()+":"+o.getAddress());          //getUserid没有和数据库对应,所以无法获取默认为0
            }   
    }

注意:上述测试代码中,由于userid没有和数据库中的字段进行对应(user_id),所以会造成数据映射不成功而默认为0

利用ResultMap

思路:利用 ResultMap 有点类似于Hibernate中POJO类中的设置。将我们对应的属性关联到类中。
1、使用resultMap将查询结果中的订单信息映射到Orders对象中,
2、在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。

// POJO基础类
    public class Orders {   
    private User user;     //  在Orders类中配置我们的User属性 

    private int id;
    private int userid;
    private String number;
    private Date createtime;
    private String note;
}


// Mapper.xml

    public interface OrdersExtendsMapper {
        public List<Orders> findorderanduserResultMap();
    }
// Mapper.java
    <mapper namespace="com.wf.dao.OrdersExtendsMapper">

<!-- 订单查询关联用户的查询 -->
<resultMap type="com.wf.model.Orders" id="OrderUserResultMap">
    <!-- 配置映射的订单信息 -->
    <id column="id" property="id"/>
     <result column="user_id" property="userid"/>       <!--    ???????? -->
    <result column="number" property="number"/>
    <result column="createtime" property="createtime"/>
    <result column="note" property="note"/>

    <!-- 配置关联的用户信息
        association:用来映射关联查询单个对象的信息
        property :将关联信息映射到Order的哪个属性中去
        javaType 映射到那个java类中
      -->
    <association property="user" javaType="com.wf.model.User">
    <!-- id  关联查询用户的唯一标识 ,外键
        column 指定唯一标识用户信息的字段,property表示类中属性
     -->
        <id column="user_id" property="id"/>             
        <result column="username" property="username"/>
        <result column="sex" property="sex"/>
        <result column="address" property="address"/>
    </association>

</resultMap>

    <select id="findorderanduserResultMap" resultMap="OrderUserResultMap">
        SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE
        orders.user_id = user.id
    </select>

</mapper>

说明:
利用 ResultMap,我们可以利用其中的association 属性将外键关联的相关类进行映射。这也是使用ResultMap 的便利之一。

ResultType和ResultMap实现一对一查询比较

1、resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。
2、resultMap需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
3、resultMap可以实现延迟加载,resultType无法实现延迟加载。

一对多查询

实例:查询订单及订单明细的信息。
SELECT orders.*,
user.username,user.sex,user.address ,
orderdetail.id,orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_id
FROM orders,USER,orderdetail
WHERE orders.user_id = user.id AND orderdetail.orders_id = orders.id

主查询表:orders
确定关联查询表:orderdetail
联结查询:内联结

利用resultType将上边的 查询结果映射到pojo中,订单信息的就是重复。而我们对于对orders映射不能出现重复记录。所以我们这里只能利用ResultMap。

利用ResultMap

// POJO类
    public class User {
        private int id;
        private String username;
        private Date birthday;
        private String address;
        private String sex;
    }



    public class Orders {

        private User user;

        private int id;
        private int userid;
        private String number;
        private Date createtime;
        private String note;

        private List<OrdersDetail> orderdetails;  //  一对多关系设置

    }

    public class OrdersDetail {
        private int id;
        private int ordersId;
        private int itemsId;
        private int itemsNum;

    }



//Mapper.java
    public interface OrdersExtendsMapper {
        // 查询订单(关联用户)订单明细
        public List<Orders> findOrderAndDetailResultMap();
    }

//Mapper.xml
    <resultMap type="com.wf.model.Orders" id="findOrderAndDetailResultMap" >
    <!-- 配置映射的订单信息 -->
        <id column="id" property="id"/>
         <result column="user_id" property="userid"/>       
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>


        <!-- 配置关联的用户信息
            association:用来映射关联查询单个对象的信息    一对多的逆向使用
            property :将关联信息映射到Order的哪个属性中去 
            javaType 映射到那个java类中
          -->
        <association property="user" javaType="com.wf.model.User">
        <!-- id  关联查询用户的唯一标识 ,外键
            column 指定唯一标识用户信息的列     
         -->
            <id column="user_id" property="id"/>            
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>

    <!-- 订单明细信息
        一个订单包含多条明细,要使用collection进行映射         一对多使用 配置在一的一方添加属性
        collection:对关联查询的多条记录映射到集合对象中去 
        property: 将关联查询出来的多条记录映射到类中的那个属性中 list
        ofType : 指定映射到集合属性中的pojo类,list的泛型
     -->
     <collection property="orderdetails" ofType="com.wf.model.OrdersDetail">
     <!-- id 订单明细唯一标识 -->
        <id column="orderdetail_id" property="id"/>
        <result column="items_id" property="itemsId"/>
        <result column="items_num" property="itemsNum"/>
        <result column="orders_id" property="ordersId"/>
     </collection>

    </resultMap>

// 测试代码

    @Test
        public void testfindOrderAndDetailResultMap() {

            SqlSession session = sqlsessionfactory.openSession();
            OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
            List<Orders> list = orderextendsmapper.findOrderAndDetailResultMap();
            // 断点查看,打印查询4条,list存储2条,自动去重了
            for(Orders o :list){
System.out.println(o.getId()+":"+o.getUser().getId()+":"+o.getUser().getUsername()+":"+o.getUser().getAddress());
            }   
        }

注意:对于一对多或者多对一的查询,建议使用ResultMap映射进行代码编写,
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。

使用resultType实现:
将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。

多对多查询

实例:查询用户及用户购买商品信息。
查询主表是:user
关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表:
orders、orderdetail、items
联结查询:内联结

利用ResultMap

// POJO类
    public class User {
        private int id;
        private String username;
        private Date birthday;
        private String address;
        private String sex;
        private List<Orders> orderslist;    //一对多
    }

    public class Orders {
        private User user;      // 用户信息
        private int id;
        private int userid;
        private String number;
        private Date createtime;
        private String note;
        private List<OrdersDetail> orderdetails;    //商品信息存放集合
    }

    public class OrdersDetail {
        private int id;
        private int ordersId;
        private int itemsId;
        private int itemsNum;
        private Items items;    //商品信息
    }

    public class Items {
        private int id;
        private String name;
        private double price;
        private String detail;
        private String pic;
        private Date createtime;
    }

// Mapper.java
    public interface OrdersExtendsMapper {
        public List<User>  findUserAndItemResultMap();
    }

//Mapper.xml  

<!-- 用户及用户购买的商品明细 -->
<resultMap type="com.wf.model.User" id="UserAndItemResultMap">
    <!-- 映射用户信息 -->
    <id column="user_id" property="id"/>
    <result column="username" property="username"/>
    <result column="sex" property="sex"/>
    <result column="address" property="address"/>

    <!-- 订单信息
         一个用户创建多个订单    使用collection
    -->
    <collection property="orderslist" ofType="com.wf.model.Orders">
        <id column="id" property="id"/>
        <result column="user_id" property="userid"/>      
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>


        <!--  订单明细
         一个订单包含多个订单明细  所以写在订单信息里面 
         -->

        <collection property="orderdetails" ofType="com.wf.model.OrdersDetail">
             <!-- id 订单明细唯一标识 -->
            <id column="orderdetail_id" property="id"/>
            <result column="items_id" property="itemsId"/>
            <result column="items_num" property="itemsNum"/>
            <result column="orders_id" property="ordersId"/>

            <!-- 商品信息
                一个订单明细对应一个商品  
             -->
             <association property="items" javaType="com.wf.model.Items">
                 <id column="items_id" property="id"/>
                 <result column="items_name" property="name"/>
                 <result column="item_price" property="price"/>
                 <result column="item_datail" property="detail"/>
             </association>
        </collection>   
    </collection>
</resultMap>

//测试代码
@Test
    public void testfindUserAndItemResultMap() {    
        SqlSession session = sqlsessionfactory.openSession();
        OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
        List<User> list = orderextendsmapper.findUserAndItemResultMap();
        for(User o :list){
            System.out.println(o.getId()+":"+o.getUsername()+":"+o.getAddress()
        +":"+o.getOrderslist().get(0).getOrderdetails().get(0).getItems().getName());
        }   
    }

注意:我们在利用多对多的情况下,一定要主要ResultMap的嵌套关系。

猜你喜欢

转载自blog.csdn.net/sinat_28978689/article/details/74999738