项目中资源交换任务实现多表级联查询。 两表一对多关系,需要多字段查询。
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返回。
当设置交换任务为主表(一对多表中的多项表)进行多表映射查询时,会出现重复的返回数据。 发现问题出现在QueryDsl执行编译好的sql语句,看到sql语句关联变成了cross join交叉查询,无论是left join还是其他是同样情况。 解决方法需要设交换方案表(一对多表中的单项对应表)为主表,交换位置。 编译sql语句正常。
当遇到复杂、投影、动态查询时我们可以考虑使用QueryDSL做开发。以上方案可以解决大多数持久层开发问题。在使用SpringDataJPA和QueryDSL实现多表关联级联查询时,注意将一对多单项关联表设为主表进行查询。