我尝试在@Query中实现一对一关系查询。相关表结构如下
@Table("t_author")
data class Author(
@field:Id
val id: Long,
var name: String,
)
@Table("t_book")
data class Book(
@field:Id
val id: Long,
var title: String,
var authorId: Long,
var publishTime: Instant,
var author: Author? // Associated 't_author'
)
我的查询定义如下
@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<Book>
}
我尝试将上面sql的返回结果映射到Book.class,我尝试定义一个转换器。
import io.r2dbc.spi.Row
import org.springframework.core.convert.converter.Converter
import org.springframework.data.convert.ReadingConverter
import java.time.Instant
@ReadingConverter
class BookConverter : Converter<Row, Book> {
override fun convert(source: Row): Book {
println("BookConverter.convert()")
return Book(
id = source.get("id", Long::class.java)!!,
title = source.get("title", String::class.java)!!,
publishTime = source.get("publish", Instant::class.java)!!,
authorId = source.get("author_id", Long::class.java)!!,
author = Author(
id = source.get("author_id", Long::class.java)!!,
name = source.get("author_name", String::class.java)!!
)
)
}
}
并在配置类中使用,
@EnableR2dbcRepositories
@Configuration
class R2DbcConfig {
@Bean
@ConditionalOnMissingBean
fun r2dbcCustomConversions(): R2dbcCustomConversions {
println("R2DbcConfig.r2dbcCustomConversions()")
return R2dbcCustomConversions.of(
MySqlDialect.INSTANCE,
BookConverter() // use
)
}
}
最后我的测试结果如下,
@field:Autowired
lateinit var bookRepository: BookRepository
@field:Autowired
lateinit var r2dbcCustomConversions: R2dbcCustomConversions
@Test
fun testRepositoryJoin() {
val source = bookRepository.bookAndAuthorById(1L)
.log()
// println(r2dbcCustomConversions)
StepVerifier.create(source)
.expectNextMatches { // assert author is not null
it.author != null
}
.verifyComplete()
}
输出如下,
...
R2DbcConfig.r2dbcCustomConversions()
2024-01-06T09:57:26.609+08:00 INFO 3416 --- [ Test worker] com.origami.r2dbc.SpringDataR2dbcTest : Started SpringDataR2dbcTest in 3.28 seconds (process running for 5.131)
...
2024-01-06T09:57:27.780+08:00 INFO 3416 --- [ Test worker] reactor.Mono.Next.1 : onSubscribe(MonoNext.NextSubscriber)
2024-01-06T09:57:27.783+08:00 INFO 3416 --- [ Test worker] reactor.Mono.Next.1 : request(unbounded)
2024-01-06T09:57:29.124+08:00 INFO 3416 --- [actor-tcp-nio-2] reactor.Mono.Next.1 : onNext(Book(id=1, title=Origami, authorId=1, publishTime=2024-01-05T14:13:22Z, author=null))
2024-01-06T09:57:29.129+08:00 INFO 3416 --- [actor-tcp-nio-2] reactor.Mono.Next.1 : cancel()
2024-01-06T09:57:29.130+08:00 INFO 3416 --- [actor-tcp-nio-2] reactor.Mono.Next.1 : onComplete()
我们可以看到输出只包含“R2DbcConfig.r2dbcCustomConversions()”,而不包含“BookConverter.convert()”。
而且我用IDE的debug查看“r2dbcCustomConversions”的结果,发现里面有“BookConveter”,但是并没有生效。 (此 -> r2dbcCustomConversions -> 转换器)
我在上一篇中看到了它,但它不起作用,如何解决这个问题。
build.gradle.kts
:
plugins {
id("org.springframework.boot") version "3.2.1"
id("io.spring.dependency-management") version "1.1.4"
kotlin("jvm") version "1.9.21"
kotlin("plugin.spring") version "1.9.21"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
runtimeOnly("com.mysql:mysql-connector-j")
runtimeOnly("io.asyncer:r2dbc-mysql")
testImplementation("io.asyncer:r2dbc-mysql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
}
我想知道为什么转换器不起作用。我也尝试过将 Kotlin 更改为 Java 代码,但也不起作用。
我可能已经找到了解决方案,我尝试将 Spring Boot 版本更改为“3.1.6”并且它有效
plugins {
id("org.springframework.boot") version "3.1.6"
// ...
}