You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring JPA OneToMany关联查询如何合并多端属性返回单条DTO记录

实现方案

方案1:JPQL层直接聚合(依赖数据库字符串拼接函数,性能更好)

如果你的项目使用支持分组字符串拼接的数据库,直接修改RandomRecRepository的查询语句,通过分组+拼接函数实现:

@Repository
@RequiredArgsConstructor
public class RandomRecRepository {

    private final EntityManager em;

    public List<RandomRecDto> findRandomApps() {
        return em.createQuery(
                // MySQL使用GROUP_CONCAT,PostgreSQL替换为STRING_AGG(g.description, ','),Oracle替换为LISTAGG(g.description, ',') WITHIN GROUP (ORDER BY g.description)
                "select new study.weba.studyJPA.dto.RandomRecDto(i.id, i.name, GROUP_CONCAT(g.description))" +
                " from IndieApp i join i.genres g " +
                " group by i.id, i.name", RandomRecDto.class)
                .setMaxResults(12)
                .getResultList();
    }
}

该方案直接在数据库层完成聚合,执行效率更高,适合数据量较大的场景。


方案2:内存中聚合(不依赖数据库特性,兼容性更好)

如果不想绑定特定数据库,可先查询原始展开数据,再通过Stream流在应用层做分组聚合:

@Repository
@RequiredArgsConstructor
public class RandomRecRepository {

    private final EntityManager em;

    public List<RandomRecDto> findRandomApps() {
        // 先查询原始的一对多展开数据
        List<RandomRecDto> rawList = em.createQuery(
                        "select new study.weba.studyJPA.dto.RandomRecDto(i.id, i.name, g.description)" +
                                " from IndieApp i join i.genres g", RandomRecDto.class)
                .getResultList();

        // 按应用ID分组
        Map<Long, List<RandomRecDto>> appGroup = rawList.stream()
                .collect(Collectors.groupingBy(RandomRecDto::getId));

        // 构造合并分类后的DTO
        List<RandomRecDto> result = new ArrayList<>();
        for (Map.Entry<Long, List<RandomRecDto>> entry : appGroup.entrySet()) {
            List<RandomRecDto> sameAppList = entry.getValue();
            String mergedGenres = sameAppList.stream()
                    .map(RandomRecDto::getGenres)
                    .collect(Collectors.joining(", "));
            result.add(new RandomRecDto(entry.getKey(), sameAppList.get(0).getName(), mergedGenres));
        }

        // 最后做条数限制
        return result.stream().limit(12).collect(Collectors.toList());
    }
}

该方案兼容性强,不需要修改查询语句,适合数据量较小、需要适配多种数据库的场景。

内容的提问来源于stack exchange,提问作者Lazybear

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 05:30:05