表无直接关联时,如何正确使用MyBatis的collection属性?
问题描述
测试数据
t1 pk | a | b | c | other1 1 | text1 | 123 | text3 | otherValues1 2 | text2 | 456 | text4 | otherValues2 t2 pk | fk | d | e | other2 1 | 1 | text5 | 10 | otherValues3 2 | 1 | text6 | 20 | otherValues4 3 | 1 | text7 | 30 | otherValues5 4 | 2 | text8 | 40 | otherValues6
实体类
@Data public class Pojo1 { private String p11; private Integer p12; private String p13; private List<Pojo2> list; } @Data public class Pojo2 { private String p21; private Integer p22; }
期望输出
{ "p11": "text1", "p12": 123, "p13": "text3", "list": [ {"p21":"text5","p22":10}, {"p21":"text6","p22":20}, {"p21":"text7","p22":30} ] }
限制条件
- 响应属性与数据库列名不一致,需要映射
- 必须分开执行两个查询,无法关联查询:
select a, b, c, other1 from table t1 where t1.pk = ${key1} select d, e, other2 from table t2 where t2.fk = ${key1}
当前配置及问题
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="something.MyMapper"> <resultMap id="map1" type="Pojo1"> <result column="a" property="p11"/> <result column="b" property="p12"/> <result column="c" property="p13"/> <collection property="list" column="dontKnowWhatToPutHere" ofType="Pojo2" select="select2"/> </resultMap> <select id="select1" resultMap="map1"> select a, b, c, other1 from table t1 where t1.pk = ${key1} </select> <resultMap id="map2" type="Pojo2"> <result column="d" property="p21"/> <result column="e" property="p22"/> </resultMap> <select id="select2" resultMap="map2"> select d, e, other2 from table t2 where t2.fk = ${key1} </select> </mapper>
当前返回结果:
{ "p11": "text1", "p12": 123, "p13": "text3", "list": null }
已知添加虚拟硬编码列的方案可行,询问是否有其他方案。
可行解决方案
除了添加虚拟硬编码列的方式,还有以下几种可行方案:
1. 主查询返回主键列,通过column传递参数
修改主查询返回t1.pk列(即使实体类无对应属性也不影响),将其作为参数传递给嵌套查询:
- 修改
select1的SQL:
select pk, a, b, c, other1 from table t1 where t1.pk = ${key1}
- 修改
map1中的collection配置:
<collection property="list" column="pk" ofType="Pojo2" select="select2"/>
- 调整
select2的SQL,使用参数占位符(推荐用#替代$防止SQL注入):
select d, e, other2 from table t2 where t2.fk = #{pk}
MyBatis会自动将主查询返回的pk值传入select2,完成关联查询并填充list。
2. Service层手动组装数据
不依赖MyBatis嵌套查询,在Service层分别调用两个Mapper方法获取数据后手动组装:
@Service public class MyService { @Autowired private MyMapper myMapper; public Pojo1 getPojo1(String key1) { Pojo1 pojo1 = myMapper.select1(key1); List<Pojo2> pojo2List = myMapper.select2(key1); pojo1.setList(pojo2List); return pojo1; } }
这种方式逻辑直观,完全由开发者控制数据组装,适合查询逻辑复杂的场景。
3. column传递固定参数(参数固定场景适用)
如果${key1}是固定值,可直接在column中硬编码参数:
<collection property="list" column="fk=${key1}" ofType="Pojo2" select="select2"/>
同时修改select2的SQL:
select d, e, other2 from table t2 where t2.fk = #{fk}
此方式灵活性差,仅适用于参数固定的场景。
内容的提问来源于stack exchange,提问作者gabriel119435
相关产品推荐
相关产品推荐

