
Hibernate 6 升级后,JPQL 中使用 new Entity(...) 构造 DTO 时若类名与实体同名,会因自动别名冲突导致 SQL 生成失败(如 missing FROM-clause entry for table "o1_0"),需显式指定 DTO 的全限定类名。
hibernate 6 升级后,jpql 中使用 `new entity(...)` 构造 dto 时若类名与实体同名,会因自动别名冲突导致 sql 生成失败(如 `missing from-clause entry for table "o1_0"`),需显式指定 dto 的全限定类名。
Hibernate 6 对 JPQL 解析和 SQL 生成逻辑进行了重构,其中一项关键变化是:当查询中同时存在同名的实体类(如 Position)和用于 SELECT NEW 的 DTO 类(也命名为 Position)时,Hibernate 不再能自动区分二者,从而在生成 SQL 时错误地将 DTO 构造器中的属性路径映射到未声明的关联表别名(如 o1_0),最终触发数据库层面的 missing FROM-clause entry 错误。
根本原因在于 Hibernate 6 强化了类型解析的严格性——它要求 new 后的类名必须唯一且无歧义。若 DTO 与实体类名相同(即使包路径不同),Hibernate 5.x 可能凭上下文容忍该写法,但 Hibernate 6 会将其视为对实体类的构造调用,并尝试按实体关系图展开关联字段(例如 p.optimizedItem.manufacturer.manufacturerId),进而引入未正确 JOIN 的隐式别名(如 o1_0),导致 SQL 编译失败。
✅ 正确做法是:始终为 SELECT NEW 中的 DTO 指定完整的包限定名,明确告知 Hibernate 这是一个独立的 DTO 类型,而非实体:
@Query("SELECT new com.example.app.dto.Position(" +
"p, " +
"CASE WHEN p.sourceSetId IS NULL THEN p.sourceSetName ELSE s.name END, " +
"pos.optimizedDisplayOrder) " +
"FROM Position p " +
"LEFT JOIN Position pos ON pos.projectId = p.projectId AND pos.positionId = p.sourceSetPositionId " +
"LEFT JOIN Manufacturer m ON p.optimizedItem.manufacturer.manufacturerId = m.manufacturerId " +
"LEFT JOIN Set s ON p.sourceSetId = s.setId AND p.projectId = s.projectId " +
"WHERE p.setId = :setId AND p.projectId = :projectId " +
"AND (UPPER(p.optimizedItem.code) LIKE UPPER(CONCAT('%', :searchParam, '%')) " +
"OR UPPER(m.name) LIKE UPPER(CONCAT('%', :searchParam, '%')) " +
"OR UPPER(p.optimizedItem.description) LIKE UPPER(CONCAT('%', :searchParam, '%')))")
List<position> findPositionsBySetAndSearch(@Param("setId") Long setId,
@Param("projectId") Long projectId,
@Param("searchParam") String searchParam);</position>
⚠️ 注意事项:
- 不要依赖 IDE 自动导入或简写类名——new Position(...) 在 Hibernate 6 中默认指向实体类;
- 确保 DTO 类具有匹配参数顺序与类型的公共构造函数(Hibernate 通过反射调用);
- 若 DTO 位于模块化项目中,请验证其是否被正确编译并包含在 classpath 中;
- 建议将 DTO 类命名与实体区分开(如 PositionDto 或 PositionSummary),从根本上避免命名冲突;
- 对于复杂查询,可考虑改用 @SqlResultSetMapping + @NamedNativeQuery 或 Spring Data JPA 的投影接口(interface PositionProjection { ... }),提升可维护性与类型安全性。
升级至 Hibernate 6 后,此类问题并非孤立案例,而是类型解析严格化带来的系统性调整。统一采用全限定名构造 DTO,既是兼容性保障,也是代码清晰性与长期可维护性的最佳实践。











