拥有这个实体:
data class Avatar(
// id is generated by postgres default value
@Id
val id: UUID? = null,
val userId: Long,
var avatar: ByteArray,
)
这个架构:
CREATE TABLE avatar (
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id bigint NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,
avatar bytea NOT NULL
);
这个存储库:
@Repository
interface AvatarRepository : CoroutineCrudRepository<Avatar, UUID> {
@Query("SELECT user_id FROM avatar WHERE id = :avatarId")
suspend fun findUserIdById(avatarId: UUID): Long?
}
我可以保存和获取实体,但是在删除时@Query
我不能使用findUserIdById
来仅加载userId
属性:
internal class AvatarRepositoryTest : RepositoryTest() {
@Autowired
private lateinit var avatarRepository: AvatarRepository
@Test
fun findUserIdById() {
setupDevData()
val expectedUserId = 1L
val bytes = byteArrayOf(0x2E)
runBlocking {
val stored = avatarRepository.save(Avatar(
id = null,
userId = expectedUserId,
avatar = bytes,
))
assertThat(stored.id).isNotNull
// ----------> the next line fails WITHOUT THE @Query("...") annotation <----------
val actual = avatarRepository.findUserIdById(stored.id!!)
assertThat(actual).isEqualTo(expectedUserId)
}
}
}
导致此错误:
Failed to convert from type [io.r2dbc.postgresql.PostgresqlRow] to type [java.lang.Long] for value 'PostgresqlRow{context=ConnectionContext{client=io.r2dbc.postgresql.client.ReactorNettyClient@8e0755, codecs=io.r2dbc.postgresql.codec.DefaultCodecs@7fecd70a, connection=PostgresqlConnection{client=io.r2dbc.postgresql.client.ReactorNettyClient@8e0755, codecs=io.r2dbc.postgresql.codec.DefaultCodecs@7fecd70a}, configuration=PostgresqlConnectionConfiguration{applicationName='r2dbc-postgresql', autodetectExtensions='true', compatibilityMode=false, connectTimeout=null, database='db', extensions=[], fetchSize=io.r2dbc.postgresql.PostgresqlConnectionConfiguration$Builder$$Lambda$862/0x000000080107d440@6974166c, forceBinary='false', host='localhost', loopResources='null', options='{}', password='****', port=49416, preferAttachedBuffers=false, socket=null, tcpKeepAlive=false, tcpNoDelay=true, username='test'}, portalNameSupplier=io.r2dbc.postgresql.DefaultPortalNameSupplier@6bfe38c7, statementCache=IndefiniteStatementCache{cache={SELECT avatar.id, avatar.user_id, avatar.avatar FROM avatar WHERE avatar.id = $1={[I@1b3a3e42=S_0}}, counter=1}}, columns=[Field{column=1, dataType=2950, dataTypeModifier=-1, dataTypeSize=16, format=FORMAT_TEXT, name='id', table=16419}, Field{column=2, dataType=20, dataTypeModifier=-1, dataTypeSize=8, format=FORMAT_TEXT, name='user_id', table=16419}, Field{column=3, dataType=17, dataTypeModifier=-1, dataTypeSize=-1, format=FORMAT_TEXT, name='avatar', table=16419}], isReleased=false}'; nested exception is java.lang.ClassCastException: class java.util.UUID cannot be cast to class java.lang.Number (java.util.UUID and java.lang.Number are in module java.base of loader 'bootstrap')
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [io.r2dbc.postgresql.PostgresqlRow] to type [java.lang.Long] for value 'PostgresqlRow{context=ConnectionContext{client=io.r2dbc.postgresql.client.ReactorNettyClient@8e0755, codecs=io.r2dbc.postgresql.codec.DefaultCodecs@7fecd70a, connection=PostgresqlConnection{client=io.r2dbc.postgresql.client.ReactorNettyClient@8e0755, codecs=io.r2dbc.postgresql.codec.DefaultCodecs@7fecd70a}, configuration=PostgresqlConnectionConfiguration{applicationName='r2dbc-postgresql', autodetectExtensions='true', compatibilityMode=false, connectTimeout=null, database='db', extensions=[], fetchSize=io.r2dbc.postgresql.PostgresqlConnectionConfiguration$Builder$$Lambda$862/0x000000080107d440@6974166c, forceBinary='false', host='localhost', loopResources='null', options='{}', password='****', port=49416, preferAttachedBuffers=false, socket=null, tcpKeepAlive=false, tcpNoDelay=true, username='test'}, portalNameSupplier=io.r2dbc.postgresql.DefaultPortalNameSupplier@6bfe38c7, statementCache=IndefiniteStatementCache{cache={SELECT avatar.id, avatar.user_id, avatar.avatar FROM avatar WHERE avatar.id = $1={[I@1b3a3e42=S_0}}, counter=1}}, columns=[Field{column=1, dataType=2950, dataTypeModifier=-1, dataTypeSize=16, format=FORMAT_TEXT, name='id', table=16419}, Field{column=2, dataType=20, dataTypeModifier=-1, dataTypeSize=8, format=FORMAT_TEXT, name='user_id', table=16419}, Field{column=3, dataType=17, dataTypeModifier=-1, dataTypeSize=-1, format=FORMAT_TEXT, name='avatar', table=16419}], isReleased=false}'; nested exception is java.lang.ClassCastException: class java.util.UUID cannot be cast to class java.lang.Number (java.util.UUID and java.lang.Number are in module java.base of loader 'bootstrap')
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:116)
at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46)
at org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery.lambda$executeQuery$2(AbstractR2dbcQuery.java:111)
at io.r2dbc.postgresql.PostgresqlResult.lambda$map$1(PostgresqlResult.java:111)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:102)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250)
at org.springframework.security.test.context.support.ReactorContextTestExecutionListener$DelegateTestExecutionListener$SecuritySubContext.onNext(ReactorContextTestExecutionListener.java:120)
at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:184)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
at io.r2dbc.postgresql.util.FluxDiscardOnCancel$FluxDiscardOnCancelSubscriber.onNext(FluxDiscardOnCancel.java:86)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:793)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.next(FluxCreate.java:718)
at reactor.core.publisher.FluxCreate$SerializedFluxSink.next(FluxCreate.java:154)
at io.r2dbc.postgresql.client.ReactorNettyClient$Conversation.emit(ReactorNettyClient.java:735)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.emit(ReactorNettyClient.java:986)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:860)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:767)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:118)
at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:220)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:220)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:280)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:389)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:401)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:311)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:432)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.ClassCastException: class java.util.UUID cannot be cast to class java.lang.Number (java.util.UUID and java.lang.Number are in module java.base of loader 'bootstrap')
at org.springframework.data.r2dbc.convert.R2dbcConverters$RowToNumberConverterFactory$RowToNumber.convert(R2dbcConverters.java:191)
at org.springframework.data.r2dbc.convert.R2dbcConverters$RowToNumberConverterFactory$RowToNumber.convert(R2dbcConverters.java:178)
at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:437)
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
... 50 more
我以为这是支持?