Mybatis一对多查询 ,以及会遇到的各种问题解答
- 业务场景
- 实体类,数据库
- 方法1:连表查询,用ResultMap映射
- 方法2:子查询进行映射
业务场景
有时候前端需要表格里面嵌套表格的情况,用以展示更加详细的信息,提高用户体验。
例如:
实体类,数据库
而此时就需要后端返回复杂的数据结构实体类中嵌套实体类的情况了。
例如:主表 PlnOrderPool.java(为节省空间 实体类中都未写get,set方法。)
附表:PlnOrderPoolDetail.java
订单主表:
订单附表:
方法1:连表查询,用ResultMap映射
注意事项:见图片中
图片上最后的where是没有的(sorry)
代码:
<resultMap id="orderAndDetail" type="org.jeecg.modules.pln.infrastructure.dao.entity.PlnOrderPool">
<id property="orderNo" column="order_no"/>
<result property="name" column="name"/>
<result property="customerName" column="customer_name"/>
<collection property="detailList" ofType="org.jeecg.modules.pln.infrastructure.dao.entity.PlnOrderPoolDetail">
<id property="id" column="d_id"/>
<result property="deliverTime" column="deliver_time"/>
<result property="deliverNum" column="deliver_num"/>
</collection>
</resultMap>
<select id="getOrderAndDetail" resultMap="orderAndDetail">
SELECT
pop.order_no,
pop.NAME,
pop.customer_name,
popd.id d_id,
popd.deliver_time,
popd.deliver_num
FROM
pln_order_pool pop
LEFT JOIN pln_order_pool_detail popd ON pop.order_no = popd.order_id
</select>
结果:
{
"message": "success",
"code": 0,
"data": [
{
"orderNo": "ORDER2022092900005",
"customerName": "上汽大通",
"name": "冷却模块",
"detailList": [
{
"id": "1575280472165048321",
"deliverNum": 60.0,
"deliverTime": "2022-10-07",
}
]
},
{
"orderNo": "ORDER2022092900006",
"customerName": "上汽大通",
"name": "冷却模块",
"detailList": [
{
"id": "1575280472177631234",
"deliverNum": 80.0,
"deliverTime": "2022-10-08",
},
{
"id": "1575280472177631235",
"deliverNum": 78.0,
"deliverTime": "2022-10-19",
}
]
},
{
"orderNo": "ORDER2022092900007",
"customerName": "无通",
"name": "散成",
"detailList": [
{
"id": "1575280472177631236",
"deliverNum": 240.0,
"deliverTime": "2022-10-07",
},
{
"id": "1575280472186019841",
"deliverNum": 240.0,
"deliverTime": "2022-10-08",
},
{
"id": "1575280472186019842",
"deliverNum": 240.0,
"deliverTime": "2022-10-09",
},
{
"id": "1575280472186019843",
"deliverNum": 240.0,
"deliverTime": "2022-10-10",
}
]
}
]
}
原理:先查询出所有数据,然后根据你规定的resultMap映射关系,去组建数据结构。 property 对应你的实体类中的属性名,column 对应你sql查出来的字段名。
并且他是根据你的<id property="orderNo" column="order_no"/>
去确定谁能代表一条主表数据,类似于分组。
优点:效率较高只需要一次查库操作,操作方便过滤条件写在一个sql中
缺点:根据主表进行分页查询比较难以实现
方法2:子查询进行映射
注意事项:
1:子查询collection中column中的值写法;
column值有两种写法:
(一),如果下图中1和4的值相同,可以直接写一个,类似于:column="xxx"
(二),下图中写法,如果有多个参数可用逗号分隔,例如:column="{d_orderNo=order_no,xxx=xxx,...}"
2:select 中的值应该为:子查询在mapper中的全路径。
代码:
<resultMap id="orderAll" type="org.jeecg.modules.pln.infrastructure.dao.entity.PlnOrderPool">
<id property="orderNo" column="order_no" />
<result property="name" column="name" />
<result property="customerName" column="customer_name" />
<collection property="detailList"
ofType="org.jeecg.modules.pln.infrastructure.dao.entity.PlnOrderPoolDetail"
select="org.jeecg.modules.pln.infrastructure.dao.mapper.PlnOrderPoolMapper.getDetailAll"
column="{d_orderNo=order_no}"></collection>
</resultMap>
<!-- 主表的在resultMap中标识了id的必须唯一-->
<select id="getAll" resultMap="orderAll">
select order_no,name,customer_name from pln_order_pool where order_no = #{orderNo}
</select>
<select id="getDetailAll" resultType="org.jeecg.modules.pln.infrastructure.dao.entity.PlnOrderPoolDetail">
select order_id,deliver_time,deliver_num from pln_order_pool_detail where order_id = #{d_orderNo}
</select>
原理:这种写法是先去查询主表然后再去根据主表中的条件去查询附表,是要进行n+1次数据库交互的。
缺点:要进行n+1次数据库交互,效率低。子查询传参过滤比较复杂
优点:无论是分页还是普通查询都能满足