Querydsl JPASQLQuery使用java.sql.Date而非java.time.LocalDate问题排查
问题原因分析
你遇到的argument type mismatch异常,核心原因是使用JPASQLQuery(原生SQL查询模式)时,QueryDSL不会自动将JDBC返回的java.sql.Date转换为LocalDate:
JPASQLQuery基于原生SQL查询,直接返回JDBC驱动提供的类型(PostgreSQL的date类型对应JDBC的java.sql.Date);- 虽然实体类和DTO中定义的是
LocalDate,但原生SQL查询结果不会经过Hibernate的JSR310类型转换器处理,导致QueryDSL尝试将java.sql.Date赋值给DTO的LocalDate字段时,出现类型不匹配。
解决方案
根据需求,有两种可行的解决路径:
方案1:改用JPAQuery(JPQL查询)
如果不需要原生SQL的特殊语法,推荐使用基于JPQL的JPAQuery,它会通过Hibernate自动处理JSR310类型转换:
final QTestEntity qTestEntity = QTestEntity.testEntity; final JPAQuery<TestEntityDto> query = new JPAQuery<>(this.db.getEntityManager()) .select(Projections.bean(TestEntityDto.class, qTestEntity.id, qTestEntity.title, qTestEntity.createdAt)) .from(qTestEntity); final List<TestEntityDto> rows = query.fetch();
这种方式完全复用Hibernate的类型映射能力,无需额外处理转换逻辑。
方案2:在原生SQL查询中显式处理类型转换
如果必须使用JPASQLQuery,可以通过以下两种方式解决:
方式A:给DTO添加转换构造器
修改DTO,新增一个接受java.sql.Date的构造器,在构造器内完成类型转换:
@Data public class TestEntityDto { private Long id; private String title; private LocalDate createdAt; // 新增构造器用于QueryDSL投影 public TestEntityDto(Long id, String title, java.sql.Date createdAt) { this.id = id; this.title = title; this.createdAt = createdAt != null ? createdAt.toLocalDate() : null; } }
然后查询时改用Projections.constructor:
final JPASQLQuery<TestEntityDto> query = new JPASQLQuery<>(this.db.getEntityManager(), new PostgreSQLTemplates()) .select(Projections.constructor(TestEntityDto.class, qTestEntity.id, qTestEntity.title, qTestEntity.createdAt)) .from(qTestEntity);
方式B:在查询中显式转换字段类型
使用QueryDSL的表达式工具,在查询时将java.sql.Date转换为LocalDate:
final JPASQLQuery<TestEntityDto> query = new JPASQLQuery<>(this.db.getEntityManager(), new PostgreSQLTemplates()) .select(Projections.bean(TestEntityDto.class, qTestEntity.id, qTestEntity.title, // 显式转换类型 ExpressionUtils.as( Expressions.dateTemplate(LocalDate.class, "{0}::date", qTestEntity.createdAt), "createdAt" ))) .from(qTestEntity);
总结
这并非QueryDSL的bug,而是原生SQL查询与JPQL查询的类型处理机制差异导致的。优先推荐方案1(改用JPAQuery),它更简洁且符合JPA的类型映射规范;如果必须使用原生SQL,则选择方案2中的任一方式处理类型转换即可。
内容的提问来源于stack exchange,提问作者Anatoliy Golubev
相关产品推荐
相关产品推荐

