![Java EE轻量级框架应用实战:SSM框架(Spring MVC+Spring+MyBatis)](https://wfqqreader-1252317822.image.myqcloud.com/cover/921/32517921/b_32517921.jpg)
4.3 一对多(collection)
与一对一的关联关系相比,开发人员接触更多的关联关系是一对多(或多对一)。如一个用户可以有多个订单,同时多个订单归一个用户所有。用户和订单的关联关系如图4.5所示。那么如何使用MyBatis框架处理这种一对多关联关系呢?在讲解过的<resultMap>元素中,包含一个<collection>子元素,MyBatis框架就是通过该子元素来处理一对多关联关系的。<collection>元素的大部分属性与<association>子元素相同,但其还包含一个特殊属性—ofType。ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_47.jpg?sign=1739044298-bVpkcvgzy58Y6ApxFaN6yCtoL38OlznC-0-d94001c4ea3b6cc09208e7deeefa80ab)
图4.5 用户和订单的关联关系
<collection>元素的使用非常简单,可以参考如下两种示例进行配置,具体代码如下:
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_48.jpg?sign=1739044298-X1Z7JD6L5fPRbcARTrqq1sa0hqNWYj3t-0-91e56c087ed50dddade04cb639a53e74)
collection的作用和association的作用都是映射到JavaBem的某个“复杂类型”属性,只不过这个属性是一个集合列表,即JavaBean内部嵌套一个复杂数据类型(集合)属性。
4.3.1 应用案例:用户角色关联用户信息
下面通过一个示例来演示collection的具体应用,示例需求:获取指定用户角色类型的相关用户信息列表。从不同角度出发映射关系的使用不同,可使用用户角色表关联用户表来实现一对多关联,具体实现步骤如下。
(1)MyBatisUtils.java、mybatis-config.xml和log4j.properties等文件请参考相关项目内容,此处不再赘述。
(2)创建POJO:Role.java,可根据数据库表(tb_role)设计相应的属性,并增加getter方法和setter方法,见示例15。
【示例15】 Role.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_50.jpg?sign=1739044298-jabOpwtFh5qqIWl4oJA3zJVWZJcsda6Z-0-b4cfc6c41e824a8d7f66a4306f24d34f)
通过以上改造,在JavaBean: Role对象内部嵌套了一个复杂数据类型的属性(users)。
(3)接下来在RoleMapper接口中增加根据用户id获取用户信息,以及地址列表的方法,见示例16。
【示例16】 RoleMapper.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_52.jpg?sign=1739044298-yXL7JuWiPUAHVsGquT9SZ9RBBryswtcq-0-5df6f271c12228f5aa836c6d0eba6f0a)
(4)修改对应RoleMapper.xml,以增加getRole。该select查询语句返回类型为resultMap,并且引用外部的resultMap类型为role。由于role对象内嵌集合对象(users),因此需要使用collection来实现结果映射,见示例17。
【示例17】 RoleMapper.xml
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_54.jpg?sign=1739044298-Kt0Xlzzbb5SigwE7koq8V9RYYG9cCzQQ-0-a09c74d42205d3c253f24b3f6059de44)
其中,使用collection元素嵌套结果的方式处理同使用association元素一样,因此,使用嵌套结果,或者从连接中嵌套查询,这两种使用方式类似,由于在实战项目中以使用嵌套结果的方式为主,嵌套查询的使用此处不再赘述。
(5)最后修改测试类UserMapperTest.java,以增加测试方法getRoleListTest(),见示例18。
【示例18】 UserMapperTest.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_56.jpg?sign=1739044298-7bfmLpv2sKVpjL7uvWZivdRf1OSsAvGr-0-089a985b0775df8b66ce8c4ccf5704e3)
在测试方法中调用getRoleListTest()方法获取userList,并进行结果输出,关键是映射用户角色的相关信息,结果输出如下:
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_57.jpg?sign=1739044298-rLiTUg4YqkWYQshJNepJVFqRJyr6gz9B-0-1d18f0af4f6277d05dfa08a457364f23)
从运行结果可以看出,使用MyBatis框架嵌套结果的方式查询出了用户权限及其关联的用户集合信息。这就是MyBatis框架一对多的关联查询。
需要注意的是,上述案例如果从用户权限的角度出发,用户权限与用户之间是一对多的关联关系,但如果从单个用户的角度出发,一个用户只能属于一个用户权限,即一对一的关联关系。可根据已学内容实现单个用户与用户权限之间的一对一关联关系。
4.3.2 应用案例:商品类型关联商品信息
下面再通过一个示例来演示collection的具体应用,示例需求:获取指定商品类型的相关商品信息列表,具体实现步骤如下。
(1)MyBatisUtils.java、mybatis-config.xml和log4j.properties等文件请参考前面项目内容,此处不再赘述。
(2)创建POJO:ProductCategory.java,可根据数据库表(tb_product_category)设计相应的属性,并增加getter方法和setter方法,见示例19。
【示例19】 ProductCategory.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_59.jpg?sign=1739044298-qpHQjlcC3sBBCdVLfA93LyrPkxm2H0g5-0-8aa1d9eb86d0c7e623fce56c62af2b8d)
通过以上改造,在JavaBean:ProductCategory对象内部嵌套了一个复杂数据类型的属性(products)。
(3)接下来在接口ProductMapper.java中增加根据用户id获取用户信息以及地址列表的方法,见示例20。
【示例20】 ProductMapper.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_61.jpg?sign=1739044298-C3bUl4UPT79XL5n1uPGKWbwzTOScEBeH-0-8ecf538d8dec918e0c229faa5fe3cef1)
(4)修改对应的ProductMapper.xml,以增加getProduct。该select查询语句返回类型为resultMap,并且引用外部的resultMap类型为ProductCategory。由于ProductCategory对象内嵌集合对象(Product),因此需要使用collection来实现结果映射,见示例21。
【示例21】 ProductMapper.xml
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_63.jpg?sign=1739044298-RpTddz3v3qPpdbusOO2VW0NhciwKHWyy-0-870acdde2cc1129a80dc370aab56c3f9)
根据上述代码,简单分析collection的属性。
①ofType:指完整Java类名或者别名,即集合所包含的类型。此处为Product。
②property:指映射数据库列的实体对象属性。此处为在ProductCategory里定义的属性(products)。
对于collection的这段代码:
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_64.jpg?sign=1739044298-xZ2SGlPV00EZFqf9pj5avMzvsec7HSQl-0-cfea50b506fb5c69c2743e832109e077)
可以理解为一个名为products,且元素类型为ProductCategory的ArrayList集合。
collection与association的功能基本一致,此处不再赘述。
(5)最后修改测试类ProductMapperTest.java,以增加测试方法getProductListTest(),见示例22。
【示例22】 ProductMapperTest.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_66.jpg?sign=1739044298-S66IfVkxMJYz0i0EvC4V1eOO0ytgzQWz-0-7a03e5dcee82603dded7536d3489e437)
在测试方法中调用getProductListTest()方法获取pList,并进行结果输出,关键是映射商品的相关信息,需要进一步循环productCategory.getProducts()进行输出。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt004_67.jpg?sign=1739044298-VLqbZjcmMsk4VEVxWmXrPehii0UsvP8I-0-5c0f3cb79b9bd6a847b29b7d66dbe29e)
通过上述代码不难发现,同association元素的resultMap属性用法基本是一样的,在此不再赘述。
4.3.3 技能训练
上机练习2 获取供应商及其采购订单列表(collection)
需求说明
(1)在上机练习1的基础上,根据指定的供应商(id)查询出其相关信息,以及其中所有的订单列表。
(2)查询结果列显示:供应商id、供应商编码、供应商名称、供应商联系人、供应商联系电话、订单列表信息(订单编码、商品名称、订单金额、是否付款)。
(3)在resultMap中使用collection子元素完成内部嵌套。
(1)修改Provider类,以增加集合类型属性(List<Bill>billList)。
(2)编写SQL查询语句(连表查询)。
(3)创建resultMap自定义映射结果,并在select中引用。