欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

QueryDsl与SpringDataJPA实现分页级联查询出现重复数据

程序员文章站 2022-03-07 10:49:18
...

QueryDsl与SpringDataJPA实现分页级联查询出现重复数据

1.需求

项目中资源交换任务实现多表级联查询。
两表一对多关系,需要多字段查询。

2.界面

QueryDsl与SpringDataJPA实现分页级联查询出现重复数据

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,简单清晰了很多。
多表投影查询示例:
QueryDsl与SpringDataJPA实现分页级联查询出现重复数据
把集合封装成Page返回。

4.重复数据问题

当设置交换任务为主表(一对多表中的多项表)进行多表映射查询时,会出现重复的返回数据。
QueryDsl与SpringDataJPA实现分页级联查询出现重复数据
发现问题出现在QueryDsl执行编译好的sql语句,看到sql语句关联变成了cross join交叉查询,无论是left join还是其他是同样情况。
QueryDsl与SpringDataJPA实现分页级联查询出现重复数据
解决方法需要设交换方案表(一对多表中的单项对应表)为主表,交换位置。
QueryDsl与SpringDataJPA实现分页级联查询出现重复数据
编译sql语句正常。
QueryDsl与SpringDataJPA实现分页级联查询出现重复数据

5.总结

当遇到复杂、投影、动态查询时我们可以考虑使用QueryDSL做开发。以上方案可以解决大多数持久层开发问题。在使用SpringDataJPA和QueryDSL实现多表关联级联查询时,注意将一对多单项关联表设为主表进行查询。