mybatis 13: 一对多关联查询

2年前 (2022) 程序员胖胖胖虎阿
267 0 0

业务背景

根据客户id查询客户基本信息,以及客户存在的订单信息

两张数据表

  • 客户表

mybatis 13: 一对多关联查询

  • 订单表

mybatis 13: 一对多关联查询

实体类

  • 客户实体类:Customer
    private Integer id;
    private String name;
    private Integer age;

    //封装存在的订单信息
    List<Order> orders = new ArrayList<>();
  • 订单实体类:Order
   private Integer id;
   private String orderNumber;
   private Double orderPrice;

CustomerMapper.java接口

    //根据客户id查询客户基本信息,以及客户存在的订单信息
    Customer getCustomerById(Integer id);

CustomerMapper.xml映射文件

    <!--
        //根据客户id查询客户基本信息,以及客户存在的订单信息
        Customer getCustomerById(Integer id);

        Customer实体类:
        private Integer id;
        private String name;
        private Integer age;

        List<Order> orders = new ArrayList<>();


        Order实体类:
        private Integer id;
        private String orderNumber;
        private Double orderPrice;
    -->


    <!-- 查询结果的映射规则-->
    <resultMap id="customerMap" type="customer">
        <!-- 主键映射 -->
        <id property="id" column="cid"/>
        <!-- 非主键映射 -->
        <result property="name" column="name"/>
        <result property="age" column="age"/>

        <!-- 定义数据容器的映射规则 -->
        <collection property="orders" ofType="order">
            <!-- 容器中元素的映射规则 -->
            <id property="id" column="oid"/>
            <result property="orderNumber" column="orderNumber"/>
            <result property="orderPrice" column="orderPrice" />
        </collection>
    </resultMap>


    <!-- 核心标签 -->
    <select id="getCustomerById" parameterType="int" resultMap="customerMap">
            select
                c.id cid, name, age, o.id oid, orderNumber, orderPrice, customer_id
            from
                customers c
            left join
                orders o
            on
                c.id=o.customer_id
            where
                c.id=#{id}
    </select>

测试

    //SqlSession对象
    SqlSession sqlSession;

    //获取CustomerMapper的mybatis动态代理对象
    CustomerMapper customerMapper;

    //获取SqlSession
    @Before
    public void getSqlSession() throws IOException {
        //读取核心配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //获取SqlSession
        sqlSession = factory.openSession();
        //获取各Mapper接口的mybatis动态代理对象
        customerMapper = sqlSession.getMapper(CustomerMapper.class);
    }

    //归还SqlSession
    @After
    public void closeSession(){
        sqlSession.close();
    }

	//测试查询标签
    @Test
    public void testGetCustomerById(){
        Customer customer = customerMapper.getCustomerById(1);
        System.out.println(customer);
    }

结果

==>  Preparing:

select 
    c.id cid, name, age, o.id oid, orderNumber, orderPrice, customer_id 
from
    customers c 
left join 
    orders o 
on 
    c.id=o.customer_id 
where 
    c.id=?
    
==> Parameters: 1(Integer)
    
<==    Columns: cid, name, age, oid, orderNumber, orderPrice, customer_id
<==        Row: 1, 荷包蛋, 22, 11, 20, 22.22, 1
<==        Row: 1, 荷包蛋, 22, 12, 60, 16.66, 1
<==      Total: 2
    
Customer{id=1, 
         name='荷包蛋', 
         age=22, 
         orders=[
         Order{id=11, orderNumber='20', orderPrice=22.22}, 
         Order{id=12, orderNumber='60', orderPrice=16.66}
         ]
        }

结果分析

  • sql语句的查询结果
<==    Columns: cid, name, age, oid, orderNumber, orderPrice, customer_id
<==        Row: 1, 荷包蛋, 22, 11, 20, 22.22, 1
<==        Row: 1, 荷包蛋, 22, 12, 60, 16.66, 1
<==      Total: 2
  • 实际注入到实体类中的数据
Customer{id=1, 
         name='荷包蛋', 
         age=22, 
         orders=[
         Order{id=11, orderNumber='20', orderPrice=22.22}, 
         Order{id=12, orderNumber='60', orderPrice=16.66}
         ]
        }
  • mybatis框架对查询结果会自动去重,按照查询结果的映射规则,完成数据向实体类的注入操作
    • 将"1, 荷包蛋, 22 "分别注入到实体类Customer的前三个简单属性中,只注入一组
    • 将关联查询到的两条订单数据分别注入到Order实体类中的对应属性中
      • 并将Order对象封装到集合中
    • 最后将Customer的三个属性值和orders集合封装成一个Customer对象返回
    • 由于在数据映射标签中没有指明对customer_id的映射规则,所以在查询时会显示该字段数据,但是并没有被注入到实体类中

注意

在一对多关联查询时,注意根据实际业务需求选择合适的连接查询语句,在本例中选择:左外连接

如果选择内连接,当用户未下订单时,查询不到用户信息

  • 外连接查询结果:无订单信息,且用户信息可以正常显示
==>  Preparing: select c.id cid, name, age, o.id oid, orderNumber, orderPrice, customer_id from customers c left join orders o on c.id=o.customer_id where c.id=?
==> Parameters: 3(Integer)
    
<==    Columns: cid, name, age, oid, orderNumber, orderPrice, customer_id
<==        Row: 3, 小张, 24, null, null, null, null
<==      Total: 1
    
Customer{id=3, name='小张', age=24, orders=[]}
  • 内连接查询结果:无订单信息,则用户信息也无法正常显示
==>  Preparing: select c.id cid, name, age, o.id oid, orderNumber, orderPrice, customer_id from customers c join orders o on c.id=o.customer_id where c.id=?
==> Parameters: 3(Integer)
<==      Total: 0
null
版权声明:程序员胖胖胖虎阿 发表于 2022年10月1日 下午3:24。
转载请注明:mybatis 13: 一对多关联查询 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...