QueryDsl与SpringDataJPA实现分页级联查询出现重复数据
程序员文章站
2022-03-07 10:49:18
...
1.需求
项目中资源交换任务实现多表级联查询。
两表一对多关系,需要多字段查询。
2.界面
3.业务代码
QueryDsl提供了对JPA,SQL,Collection,MongoDB等不同类型查询的实现。
这里讲解和SpringDataJPA集成实现多表分页级联查询。
@Override
public Page<DirExchangeCfgDetailDto> searchDetailByPage(Pageable pageable, MultiValueMap<String, String> parameters) {
if (pageable.getSort().isUnsorted()) {
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), QSort.by(qCfgEntity.createDate.desc(),qCfgDetailEntity.id.desc()));
}
Page<Tuple> tuplePage = repository.findAll(null, pageable, jpqlQuery -> jpqlQuery.from(qCfgEntity).innerJoin(qCfgDetailEntity)
.on(qCfgDetailEntity.configId.eq(qCfgEntity.id)).where(builderConditions(parameters)), qCfgDetailEntity,qCfgEntity);
return tuplePage.map(tuple -> {
DirExchangeCfgDetailDto cfgDetailDto = dtoMapper.map(tuple.get(qCfgDetailEntity), DirExchangeCfgDetailDto.class);
// 判断是否为默认任务
if (DEFAULT_EXCHANGE_CFG_CODE.equalsIgnoreCase(tuple.get(qCfgEntity).getCfgCode())) {
cfgDetailDto.setIsDefault(true);
}else {
cfgDetailDto.setIsDefault(false);
}
cfgDetailDto.setCfgName(tuple.get(qCfgEntity).getCfgName());
cfgDetailDto.setFlowDirection(tuple.get(qCfgEntity).getFlowDirection());
cfgDetailDto.setChangeType(tuple.get(qCfgEntity).getChangeType());
cfgDetailDto.setCronStr(tuple.get(qCfgEntity).getCronStr());
return cfgDetailDto;
});
}
private BooleanBuilder builderConditions(MultiValueMap<String, String> parameters) {
final String resourceName = parameters.getFirst("resourceName");
final String availableStatus = parameters.getFirst("availableStatus");
final String flowDirection = parameters.getFirst("flowDirection");
final String changeType = parameters.getFirst("changeType");
BooleanBuilder builder = new BooleanBuilder();
if (StringUtils.isNotEmpty(resourceName)) {
builder.and(qCfgDetailEntity.resourceName.eq(resourceName));
}
if (StringUtils.isNotEmpty(availableStatus)) {
builder.and(qCfgDetailEntity.availableStatus.eq(availableStatus));
}
if (StringUtils.isNotEmpty(flowDirection)) {
builder.and(qCfgEntity.flowDirection.eq(flowDirection));
}
if (StringUtils.isNotEmpty(changeType)) {
builder.and(qCfgEntity.changeType.eq(changeType));
}
return builder;
}
主要调用JPQLQuery的方法,将结果存放到一个Tuple的多元组中.相比原生sql,简单清晰了很多。
多表投影查询示例:
把集合封装成Page返回。
4.重复数据问题
当设置交换任务为主表(一对多表中的多项表)进行多表映射查询时,会出现重复的返回数据。
发现问题出现在QueryDsl执行编译好的sql语句,看到sql语句关联变成了cross join交叉查询,无论是left join还是其他是同样情况。
解决方法需要设交换方案表(一对多表中的单项对应表)为主表,交换位置。
编译sql语句正常。
5.总结
当遇到复杂、投影、动态查询时我们可以考虑使用QueryDSL做开发。以上方案可以解决大多数持久层开发问题。在使用SpringDataJPA和QueryDSL实现多表关联级联查询时,注意将一对多单项关联表设为主表进行查询。
上一篇: php怎么获取前几天的日期