You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 01:56:12