首页 > 解决方案 > R2DBC 和枚举 (PostgreSQL)

问题描述

2020 年 8 月 15 日更新:看起来Enum支持是在 6 月 16 日添加的。R2DBC 提交

H2DBC 是否支持 PostgreSQL 枚举?我检查了他们的git 页面,但没有提及任何内容。如果是这样,如何使用枚举(INSERT,SELECT)?
让我们说 PostgreSQL 枚举

CREATE TYPE mood AS ENUM ('UNKNOWN', 'HAPPY', 'SAD', ...);

Java 类

@Data
public class Person {
    private String name;
    private Mood mood;
    // ...

    enum Mood{ UNKNOWN, HAPPY, SAD, ...}
}

我试过了:

        // insert
        var person = ...;
        client.insert()
                .table("people")
                .using(person)
                .then()
                .subscribe(System.out::println);

        // select
        var query = "SELECT * FROM people";
        client.execute(query)
                .as(Person.class)
                .fetch().all()
                .subscribe(System.out::println);

但我收到错误消息:

# on insert
 WARN [reactor-tcp-epoll-1] (Loggers.java:294) - Error: SEVERITY_LOCALIZED=ERROR, SEVERITY_NON_LOCALIZED=ERROR, CODE=42804, MESSAGE=column "mood" is of type mood but expression is of type character varying, HINT=You will need to rewrite or cast the expression., POSITION=61, FILE=parse_target.c, LINE=591, ROUTINE=transformAssignedExpr
# on select
ERROR [reactor-tcp-epoll-1] (Loggers.java:319) - [id: 0x8581acdb, L:/127.0.0.1:39726 ! R:127.0.0.1/127.0.0.1:5432] Error was received while reading the incoming data. The connection will be closed.
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.mapping.MappingException: Could not read property private ...

我发现了类似的帖子,但没有运气解决我的问题..也许我应用错了..
欢迎任何帮助或提示。

标签: postgresqlenumsspring-dataspring-data-r2dbcr2dbc

解决方案


org.springframework.data:spring-data-r2dbc:1.0.0.RELEASE和测试io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE

科特林版本。

  1. 定义一个枚举类

    enum class Mood {
        UNKNOWN,
        HAPPY,
        SAD
    }
    
  2. 创建自定义编解码器

    class MoodCodec(private val allocator: ByteBufAllocator) :  Codec<Mood> {
        override fun canEncodeNull(type: Class<*>): Boolean = false
    
        override fun canEncode(value: Any): Boolean = value is Mood
    
        override fun encode(value: Any): Parameter {
            return Parameter(Format.FORMAT_TEXT, oid) {
                ByteBufUtils.encode(allocator, (value as Mood).name)
            }
        }
    
        override fun canDecode(dataType: Int, format: Format, type: Class<*>): Boolean = dataType == oid
    
        override fun decode(buffer: ByteBuf?, dataType: Int, format: Format, type: Class<out Mood>): Mood? {
            buffer ?: return null
            return Mood.valueOf(ByteBufUtils.decode(buffer))
        }
    
        override fun type(): Class<*> = Mood::class.java
    
        override fun encodeNull(): Parameter =
            Parameter(Format.FORMAT_TEXT, oid, Parameter.NULL_VALUE)
    
        companion object {
            // Get form `select oid from pg_type where typname = 'mood'`
            private const val oid = YOUR_ENUM_OID
        }
    }
    
  3. 注册编解码器

    您可能需要更改runtimeOnly("io.r2dbc:r2dbc-postgresql")implementation("io.r2dbc:r2dbc-postgresql")

    @Configuration
    @EnableR2dbcRepositories
    class AppConfig : AbstractR2dbcConfiguration() {
        override fun connectionFactory(): ConnectionFactory = PostgresqlConnectionConfiguration.builder()
            .port(5432) // Add your config here.
            .codecRegistrar { _, allocator, registry ->
                registry.addFirst(MoodCodec(allocator))
                Mono.empty()
            }.build()
            .let { PostgresqlConnectionFactory(it) }
    }
    

推荐阅读