业务上遇到了一个问题,需要进行一对多的分页查询,同时还存在对主表和子表的条件限制,经过查询后参考其他人的经验进行了处理,记录如下.
其中的坑就是正常的分页查询下,一对多的分页是错误的,它不会按主表的查询条数来返回数量,而是把主表-一个子表记录这样的形式来返回数量,导致返回数量跟预期不符.例如一个MiddleWareDto对象里nodes大小为5,应该返回数量是1,结果它会返回5.
这里使用子查询的方式来避免这个坑.
各实体类如下
public class MiddleWareDto implements Serializable {
//主表的id
private Integer groupId;
....................
//其他属性
....................
private List<MiddleWareNodeDto> nodes;
}
public class MiddleWareNodeDto {
//对应主表中的groupId
private Integer groupId;
......................
//其他属性
}
Service
@Override
public CommResponse<PageResult<MiddleWareDto>> list(MiddleWareReq req) {
Page<MiddleWareDto> page = new Page<>(req.getPageIndex(), req.getPageSize());
IPage<MiddleWareDto> list = middleWareGroupMapper.getList(page, req);
.......................
}
Mapper
mapper方法声明如下,包括主查询和子查询方法,Service中调用的是主查询方法
IPage<MiddleWareDto> getList(@Param("page") Page<MiddleWareDto> page, @Param("req") MiddleWareReq req);
List<MiddleWareNodeDto> getNodeList(Integer groupId);
xml文件编写
主查询如下:
<select id="getList" resultMap="MiddleWareDtoResultMap">
SELECT * FROM MIDDLE_WARE_GROUP w
WHERE 1=1
<if test="req.groupName != null and req.groupName != ''">
AND w.group_name like '%'+#{req.groupName}+'%'
</if>
<if test="req.type != null and req.type != ''">
ANd w.type=#{req.type}
</if>
<if test="req.hostId != null and req.hostId > 0">
AND w.group_id IN (SELECT a.group_id FROM MIDDLE_WARE_GROUP a,MIDDLE_WARE_NODE b WHERE a.group_id = b.group_id AND b.host_id=#{req.hostId})
</if>
<if test="req.ip !=null and req.ip != ''">
AND w.group_id IN (SELECT a.group_id FROM MIDDLE_WARE_GROUP a,MIDDLE_WARE_NODE b WHERE a.group_id = b.group_id AND b.ip_port LIKE '%'+#{req.ip}+'%')
</if>
</select>
可以看到主查询主要是查询的主表,查询结果通过resultMap进行了映射,就是在这里调用进行子查询.
这里前两个查询条件是对主表的限制,直接写即可;后两个条件是对子表的限制,没法直接实现,只能通过这种间接的形式来实现.
我们看一下resultMap的具体内容:
<resultMap id="MiddleWareDtoResultMap" type="com.montnets.monitor.pcweb.entity.dto.MiddleWareDto">
<id property="groupId" column="group_id"/>
<result property="groupName" column="group_name"/>
.......其他属性的映射
<collection property="nodes" ofType="com.montnets.monitor.pcweb.entity.dto.MiddleWareNodeDto"
select="getNodeList" column="group_id" javaType="ArrayList">
<result property="groupId" column="group_id"/>
......其他属性映射
</collection>
</resultMap>
这里面 collection 指的就是一对多的实现,
property 指主对象中的属性,即我们的list
ofType 指list中的类型
select 子查询语句
column 子查询的参数
javaType 子查询集合的类型,即我们的nodes的类型
最后看看我们的子查询语句
<select id="getNodeList" resultType="com.montnets.monitor.pcweb.entity.dto.MiddleWareNodeDto">
SELECT * FROM MIDDLE_WARE_NODE n
WHERE n.group_id = #{groupId}
</select>
总结一下:通过resutlMap映射的方式调用子查询,实现一对多的查询,使用自带的page分页实现,使用了间接的限制方式实现了对子表查询条件的查询