Spring Data R2DBC中Converter<Row, Entity>不生效问题求助
问题分析与解决方案
你的核心问题是Spring Data R2DBC在处理带@Table注解的实体类时,默认会使用内置的MappingR2dbcConverter进行逐属性映射,不会触发自定义的Row→Book全局转换器。以下是具体的解决思路和实现方案:
方案1:为Author类型添加专属转换器(推荐)
这种方式无需修改返回类型,直接让MappingR2dbcConverter自动将查询结果组装成Book实体的author属性。
步骤1:替换原转换器,编写Author的Row转换器
移除原来的BookConverter,新增针对Author的读取转换器,处理LEFT JOIN可能返回的null情况:
@ReadingConverter class AuthorRowConverter : Converter<Row, Author?> { override fun convert(source: Row): Author? { val authorId = source.get("author_id", Long::class.java) ?: return null val authorName = source.get("author_name", String::class.java) ?: return null return Author(authorId, authorName) } }
步骤2:更新配置类,注册新转换器
@EnableR2dbcRepositories @Configuration class R2DbcConfig { @Bean @ConditionalOnMissingBean fun r2dbcCustomConversions(): R2dbcCustomConversions { return R2dbcCustomConversions.of( MySqlDialect.INSTANCE, AuthorRowConverter() ) } }
步骤3:修正原转换器的字段错误
原代码中publishTime读取的是publish字段,实际应该对应数据库的publish_time列,这个错误会导致空指针异常,需要在后续任何实现中修正。
方案2:使用自定义DTO+转换器
如果需要完全自定义映射逻辑,可以创建不带@Table注解的DTO,让Spring Data触发全局Row转换器。
步骤1:创建DTO类
data class BookWithAuthorDTO( val id: Long, val title: String, val authorId: Long, val publishTime: Instant, val author: Author? )
步骤2:编写DTO的转换器
@ReadingConverter class BookWithAuthorConverter : Converter<Row, BookWithAuthorDTO> { override fun convert(source: Row): BookWithAuthorDTO { val authorId = source.get("author_id", Long::class.java)!! return BookWithAuthorDTO( id = source.get("id", Long::class.java)!!, title = source.get("title", String::class.java)!!, publishTime = source.get("publish_time", Instant::class.java)!!, authorId = authorId, author = source.get("author_name", String::class.java)?.let { Author(authorId, it) } ) } }
步骤3:修改Repository方法并转换为Book实体
@Repository interface BookRepository : R2dbcRepository<Book, Long> { @Query( """ SELECT b.*, a.name AS author_name FROM t_book b LEFT JOIN t_author a ON b.author_id = a.id WHERE b.id = :id """ ) fun bookAndAuthorById(@Param("id") id: Long): Mono<BookWithAuthorDTO> } // 使用时转换为Book实体 val bookMono = bookRepository.bookAndAuthorById(id) .map { dto -> Book(dto.id, dto.title, dto.authorId, dto.publishTime, dto.author) }
为什么原转换器不生效?
Spring Data R2DBC对带@Table注解的实体类,会优先使用内置的MappingR2dbcConverter进行逐列属性映射,而非全局的Row→实体转换器。只有当返回类型是未被Spring Data管理的普通类(无@Table注解)时,才会触发自定义的Row转换器。
内容的提问来源于stack exchange,提问作者Origami Tobiichi
相关产品推荐
相关产品推荐

