Hibernate Criteria查询一对多关联获取子实体报错求助
问题:查询Installer子实体infoRges时出现SQL语法错误
实体类与DTO定义
Installer实体类
@Entity @Table(name = "installer") public class Installer implements Serializable { @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<InfoRge> infoRges; @Column(name = "enterprise_name", length = 50) private String name; // 包含getter和setter }
InstallerListDto类
private Set<InfoRge> infoRges; private String name; // 构造方法:Long id, Set<InfoRge> infoRges, String name // 包含setter和getter
查询代码(Criteria Query)
// 创建CriteriaBuilder CriteriaBuilder cb = em.getCriteriaBuilder(); // 创建针对InstallerListDto的查询 CriteriaQuery<InstallerListDto> criteriaQuery = cb.createQuery(InstallerListDto.class); Root<Installer> from = criteriaQuery.from(Installer.class); criteriaQuery.select(cb.construct(InstallerListDto.class, from.get("id"), from.get("infoRges"), from.get("name")));
报错信息
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '. as col_5_0_, installer0_.enterprise_name as col_6_0_ from installer installer0' at line 1
问题原因与解决方案
原因
JPA的CriteriaBuilder.construct()仅支持映射简单属性,无法直接处理@OneToMany这类关联集合。直接将from.get("infoRges")传入构造方法时,Hibernate无法生成合法的SQL语句,导致语法错误。
解决方法
方式1:先查实体再手动转DTO
// 查询Installer实体,并主动加载关联集合避免懒加载问题 CriteriaQuery<Installer> criteriaQuery = cb.createQuery(Installer.class); Root<Installer> from = criteriaQuery.from(Installer.class); from.fetch("infoRges", JoinType.LEFT); criteriaQuery.select(from); List<Installer> installers = em.createQuery(criteriaQuery).getResultList(); // 手动转换为DTO List<InstallerListDto> dtos = installers.stream() .map(installer -> new InstallerListDto(installer.getId(), installer.getInfoRges(), installer.getName())) .collect(Collectors.toList());
该方式逻辑直观,适合数据量不大的场景,通过fetch提前加载关联集合可避免N+1查询问题。
方式2:用JPQL直接构造DTO
改用JPQL的构造函数表达式,Hibernate支持直接映射关联集合:
// 需替换为DTO的完整类路径 String jpql = "SELECT new com.yourpackage.InstallerListDto(i.id, i.infoRges, i.name) FROM Installer i LEFT JOIN FETCH i.infoRges"; List<InstallerListDto> dtos = em.createQuery(jpql, InstallerListDto.class).getResultList();
通过LEFT JOIN FETCH确保关联集合被正确加载,避免懒加载异常。
补充:完善关联映射配置
当前@OneToMany注解缺少mappedBy属性(除非InfoRge用的是单向@JoinColumn关联),建议补充配置以保证映射正确性:
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "installer") private Set<InfoRge> infoRges;
其中mappedBy的值对应InfoRge实体中指向Installer的属性名。
内容的提问来源于stack exchange,提问作者Bader-Eddine Qodia
相关产品推荐
相关产品推荐

