MyBatis的关联映射,resultMap元素之collection子元素,实现多对多关联关系(节选自:Java EE企业级应用开发教程)
MyBatis映射文件中的<resultMap>元素中,包含一个<collection>子元素,MyBatis通过它来处理多对多关联关系。
<collection>子元素的大部分属性与<association>子元素相同,但其还包含一个特殊属性——ofType。ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。
本文是MyBatis的关联映射,resultMap元素之association子元素,实现一对一关联关系(节选自:Java EE企业级应用开发教程)、MyBatis的关联映射,resultMap元素之collection子元素,实现一对多关联关系(节选自:Java EE企业级应用开发教程)两篇文章的延续,如有配置上的问题,请参考上两篇文章。
情景:在实际项目开发中,多对多的关联关系是非常觉的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单,订单和商品就属于多对多的关联关系。
一、创建数据结构及插入数据(MySQL),注意:请先选择数据库
# 创建一个名称为tb_product的表 CREATE TABLE tb_product( id INT(32) PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32), price DOUBLE ); # 插入3条数据 INSERT INTO tb_product VALUES ('1','Java基础入门','44.5'); INSERT INTO tb_product VALUES ('2','Java Web程序开发入门','38.5'); INSERT INTO tb_product VALUES ('3','SSM框架整合实战','50'); # 创建一个名称为tb_ordersitem 的中间表 CREATE TABLE tb_ordersitem( id INT(32) PRIMARY KEY AUTO_INCREMENT, orders_id INT(32), product_id INT(32), FOREIGN KEY(orders_id) REFERENCES tb_orders(id), FOREIGN KEY(product_id) REFERENCES tb_product(id) ); # 插入5条数据 INSERT INTO tb_ordersitem VALUES ('1','1','1'); INSERT INTO tb_ordersitem VALUES ('2','1','3'); INSERT INTO tb_ordersitem VALUES ('3','3','1'); INSERT INTO tb_ordersitem VALUES ('4','3','2'); INSERT INTO tb_ordersitem VALUES ('5','3','3');
二、创建实体类Product,并修改Orders实体类
package com.itheima.po; import java.util.List; /** * 商品持久化类 */ public class Product { private Integer id; //商品id private String name; //商品名称 private Double price;//商品单价 private List<Orders> orders; //与订单的关联属性 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public List<Orders> getOrders() { return orders; } public void setOrders(List<Orders> orders) { this.orders = orders; } @Override public String toString() { return "Product [id=" + id + ", name=" + name + ", price=" + price + "]"; } }
package com.itheima.po; import java.util.List; /** * 订单持久化类 */ public class Orders { private Integer id; //订单id private String number;//订单编号 //关联商品集合信息 private List<Product> productList; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public List<Product> getProductList() { return productList; } public void setProductList(List<Product> productList) { this.productList = productList; } @Override public String toString() { return "Orders [id=" + id + ", number=" + number + ", productList=" + productList + "]"; } }
三、创建映射文件ProductMapper.xml、OrdersMapper.xml
<?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.itheima.mapper.ProductMapper"> <select id="findProductById" parameterType="Integer" resultType="Product"> SELECT * from tb_product where id IN( SELECT product_id FROM tb_ordersitem WHERE orders_id = #{id} ) </select> </mapper>
<?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.itheima.mapper.OrdersMapper"> <!-- 多对多嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 --> <select id="findOrdersWithPorduct" parameterType="Integer" resultMap="OrdersWithProductResult"> select * from tb_orders WHERE id=#{id} </select> <resultMap type="Orders" id="OrdersWithProductResult"> <id property="id" column="id" /> <result property="number" column="number" /> <collection property="productList" column="id" ofType="Product" select="com.itheima.mapper.ProductMapper.findProductById"> </collection> </resultMap> <!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情 --> <select id="findOrdersWithPorduct2" parameterType="Integer" resultMap="OrdersWithPorductResult2"> select o.*,p.id as pid,p.name,p.price from tb_orders o,tb_product p,tb_ordersitem oi WHERE oi.orders_id=o.id and oi.product_id=p.id and o.id=#{id} </select> <!-- 自定义手动映射类型 --> <resultMap type="Orders" id="OrdersWithPorductResult2"> <id property="id" column="id" /> <result property="number" column="number" /> <!-- 多对多关联映射:collection --> <collection property="productList" ofType="Product"> <id property="id" column="pid" /> <result property="name" column="name" /> <result property="price" column="price" /> </collection> </resultMap> </mapper>
四、修改MyBatis配置文件(mybatis-config.xml),加入如下内容:
<mapper resource="com/itheima/mapper/OrdersMapper.xml" /> <mapper resource="com/itheima/mapper/ProductMapper.xml" />
五、修改测试程序MybatisAssociatedTest.java,加入如下内容:
可以将findOrdersWithPorduct修改为findOrdersWithPorduct2,其输出仍然是一样的。
/** * 多对多 */ @Test public void findOrdersTest(){ // 1、通过工具类生成SqlSession对象 SqlSession session = MybatisUtils.getSession(); // 2、查询id为1的订单中的商品信息 Orders orders = session.selectOne("com.itheima.mapper." + "OrdersMapper.findOrdersWithPorduct", 3); // 3、输出查询结果信息 System.out.println(orders); // 4、关闭SqlSession session.close(); }
六、运行结果
DEBUG [main] - ==> Preparing: select * from tb_orders WHERE id=? DEBUG [main] - ==> Parameters: 3(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - ==> Preparing: SELECT * from tb_product where id IN( SELECT product_id FROM tb_ordersitem WHERE orders_id = ? ) DEBUG [main] - ==> Parameters: 3(Integer) DEBUG [main] - <== Total: 3 Orders [id=3, number=1000013, productList=[Product [id=1, name=Java基础入门, price=44.5], Product [id=2, name=Java Web程序开发入门, price=38.5], Product [id=3, name=SSM框架整合实战, price=50.0]]]