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

QueryDSL中使用CollectionTable关联属性时,通过Projections.constructor构造DTO包含List<String>类型uri字段报错的解决方案问询

解决QueryDSL Projections.constructor映射@ElementCollection集合字段的「not an entity」错误

我明白你的问题:你用JPA的@ElementCollection维护goose_auth_items和goose_auth_items_uri的关联,想通过QueryDSL的Projections.constructor把查询结果映射到包含List<String> uri的DTO中,但直接传gooseAuthItems.uri会触发「not an entity」错误,去掉uri字段就正常运行。

这个问题的核心是:QueryDSL的ListPath(对应你的gooseAuthItems.uri)是集合类型的路径表达式,不能直接作为Projections.constructor的参数——构造函数需要的是具体的List<String>值,而不是一个关联路径。你得通过显式关联+分组聚合的方式,把多条uri记录合并为一个List,再映射到DTO里。

具体解决方案步骤

1. 确保DTO有对应构造函数

先检查你的GooseAuthGetItemsResponseDto是否包含带List<String> uri参数的构造函数,参数顺序要和后续select里的字段完全匹配:

public class GooseAuthGetItemsResponseDto {
    private String name;
    private String userName;
    private String userPassword;
    private String folder;
    private String notes;
    private List<String> uri = new ArrayList<>();
    private LocalDateTime updateDate;

    // 必须包含这个构造函数
    public GooseAuthGetItemsResponseDto(String name, String userName, String userPassword, String folder, String notes, List<String> uri, LocalDateTime updateDate) {
        this.name = name;
        this.userName = userName;
        this.userPassword = userPassword;
        this.folder = folder;
        this.notes = notes;
        this.uri = uri;
        this.updateDate = updateDate;
    }

    // getter/setter方法...
}

2. 修改QueryDSL查询代码

你需要显式关联goose_auth_items_uri表,通过groupBy按主实体主键分组,再用Aggregation.list()聚合uri字段为List:

// 获取QueryDSL自动生成的goose_auth_items_uri对应Q类实例
QGooseAuthItemsUri gooseAuthItemsUri = QGooseAuthItemsUri.gooseAuthItemsUri;

return queryFactory.select(
        Projections.constructor(GooseAuthGetItemsResponseDto.class,
            gooseAuthItems.name,
            gooseAuthItems.userName,
            gooseAuthItems.userPassword,
            gooseAuthItems.folder,
            gooseAuthItems.notes,
            Aggregation.list(gooseAuthItemsUri.uri), // 把分组内的uri聚合为List<String>
            gooseAuthItems.updateDate)
    )
    .from(gooseAuthItems)
    // 显式关联ElementCollection对应的表
    .leftJoin(gooseAuthItems.uri, gooseAuthItemsUri)
    .where(gooseAuthItems.userMaster.eq(userMaster))
    // 按主实体主键+其他非聚合字段分组,保证每个主实体只返回一条记录
    .groupBy(gooseAuthItems.itemIdentity, gooseAuthItems.name, gooseAuthItems.userName, gooseAuthItems.userPassword, gooseAuthItems.folder, gooseAuthItems.notes, gooseAuthItems.updateDate)
    .fetch();

3. 为什么这样能解决问题?

  • 显式leftJoin确保我们能从关联表中正确获取uri数据,避免隐式关联导致的路径解析错误;
  • groupBy按主实体的唯一标识(itemIdentity)和其他非聚合字段分组,保证每个主实体只生成一条DTO记录;
  • Aggregation.list()将分组内的所有uri值收集为一个List<String>,正好匹配DTO构造函数的参数类型,彻底解决「not an entity」的路径映射问题。

额外小技巧

如果你不想显式使用QGooseAuthItemsUri,也可以直接用gooseAuthItems.uri的元素路径来聚合,比如:

Aggregation.list(gooseAuthItems.uri)

但显式关联表的方式逻辑更清晰,也更容易排查后续可能出现的关联问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:17:27