使用QueryDSL处理带OneToMany的Embeddable时生成异常SQL问题
解决QueryDSL处理Embeddable集合属性时生成无效Oracle SQL的问题
问题场景
实体结构:
@Entity class Ent1 { @Embedded Embed embed; } @Entity class Ent2 { @ManyToOne Ent1 ent1; } @Embeddable class Embed { @OneToMany List<Ent2> ent2List; }
执行QueryDSL查询:
query .select(Projections.constructor(Embed.class, QEnt1.qEnt1.ent2List)) .from(QEnt1.qEnt1) .fetch();
生成的Oracle SQL包含无效语句 . as col0,导致查询执行失败。
解决方案
1. 手动组装Embed对象(推荐)
避免直接通过投影构造Embed,先查询关联数据,再在Java层面组装:
// 查询Ent1和对应的Ent2数据 List<Tuple> results = query .select(QEnt1.qEnt1, QEnt2.qEnt2) .from(QEnt1.qEnt1) .leftJoin(QEnt1.qEnt1.embed.ent2List, QEnt2.qEnt2) .fetch(); // 按Ent1分组,获取对应的Ent2列表 Map<Ent1, List<Ent2>> ent1Ent2Map = results.stream() .collect(Collectors.groupingBy( tuple -> tuple.get(QEnt1.qEnt1), Collectors.mapping(tuple -> tuple.get(QEnt2.qEnt2), Collectors.toList()) )); // 组装Embed对象 List<Embed> embeds = ent1Ent2Map.values().stream() .map(ent2List -> { Embed embed = new Embed(); embed.setEnt2List(ent2List); return embed; }) .collect(Collectors.toList());
2. 使用Projections.bean代替构造器投影
如果Embed类有对应的setter方法,可使用Projections.bean进行属性映射,避免生成无效SQL:
List<Embed> embeds = query .select(Projections.bean(Embed.class, QEnt1.qEnt1.embed.ent2List.as("ent2List"))) .from(QEnt1.qEnt1) .leftJoin(QEnt1.qEnt1.embed.ent2List).fetchJoin() // 确保集合被完整抓取 .fetch();
3. 升级QueryDSL版本
该问题可能是旧版本QueryDSL的兼容性bug,建议升级到最新稳定版(如5.x系列),新版本对Embeddable的集合属性投影逻辑做了优化修复。
问题根源
Embeddable属于值对象,没有独立的数据库表和主键。当直接使用Projections.constructor投影Embeddable的集合属性时,QueryDSL错误地尝试生成一个对应Embeddable本身的空列,导致Oracle SQL出现语法错误 . as col0。
内容的提问来源于stack exchange,提问作者M.eid
相关产品推荐
相关产品推荐

