Spring Data JPA原生查询返回DTO遇转换器异常,寻求Class-Based Projections修复方案
解决Spring Data JPA原生SQL查询映射Class-Based Projection的问题
方案1:通过@SqlResultSetMapping+@ConstructorResult显式映射
在实体类SigningKeysEnt上添加结果集映射规则,指定用SigningKey的构造函数来转换查询结果:
@Entity @Table(name = "signing_keys") @Getter @Setter @SqlResultSetMapping( name = "SigningKeyProjection", classes = @ConstructorResult( targetClass = SigningKey.class, columns = { @ColumnResult(name = "public_key", type = String.class), @ColumnResult(name = "protocol_version", type = String.class), @ColumnResult(name = "expiration_date", type = Date.class) } ) ) public class SigningKeysEnt { // 原有字段逻辑保持不变 }
接着修改Repository的查询注解,指定使用上述映射规则:
@Repository public interface SigningKeysRepository extends JpaRepository<SigningKeysEnt, Long> { @Query(value = """ SELECT public_key, protocol_version, expiration_date FROM signing_keys """, nativeQuery = true, resultSetMapping = "SigningKeyProjection") List<SigningKey> getPublicKeys(); }
注意:SQL中无需给字段加别名,@ColumnResult直接对应数据库表字段名,且列的顺序必须和SigningKey构造函数的参数顺序完全一致。
方案2:通过编译参数+别名匹配构造函数参数
如果不想添加映射注解,可通过以下两步实现自动映射:
- 确保编译时保留构造函数参数名(Maven配置示例):
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <!-- 匹配你的项目JDK版本 --> <target>1.8</target> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
- 修改SQL查询的别名,使其与
SigningKey构造函数的参数名完全匹配:
@Query(value = """ SELECT public_key AS publicKey, protocol_version AS protocolVersion, expiration_date AS expirationDate FROM signing_keys """, nativeQuery = true) List<SigningKey> getPublicKeys();
问题根源说明
原生SQL查询默认返回TupleBackedMap类型,Spring Data JPA不会自动将其转换为自定义DTO——即使添加了构造函数,也需要通过显式映射或参数名匹配的方式,明确告诉JPA如何将查询结果转换为目标DTO实例。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

