my-*_*my- 4 postgresql enums spring-data spring-data-r2dbc r2dbc
2020Enum年 8 月15 日更新:似乎在 6 月 16日添加了支持。R2DBC 提交。
H2DBC 是否支持 PostgreSQL 枚举?我检查了他们的git page但它没有提到任何关于它的内容。如果是这样,如何使用枚举(插入、选择)?
让我们说 PostgreSQL 枚举
CREATE TYPE mood AS ENUM ('UNKNOWN', 'HAPPY', 'SAD', ...);
Run Code Online (Sandbox Code Playgroud)
Java类
@Data
public class Person {
private String name;
private Mood mood;
// ...
enum Mood{ UNKNOWN, HAPPY, SAD, ...}
}
Run Code Online (Sandbox Code Playgroud)
我试过:
// 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);
Run Code Online (Sandbox Code Playgroud)
但我收到错误消息:
# 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 ...
Run Code Online (Sandbox Code Playgroud)
我找到了类似的帖子,但没有运气来解决我的问题..也许我应用错了..
欢迎任何帮助或提示。
用org.springframework.data:spring-data-r2dbc:1.0.0.RELEASE和测试io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE。
科特林版。
定义一个枚举类
enum class Mood {
UNKNOWN,
HAPPY,
SAD
}
Run Code Online (Sandbox Code Playgroud)创建自定义编解码器
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
}
}
Run Code Online (Sandbox Code Playgroud)注册编解码器
您可能需要更改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) }
}
Run Code Online (Sandbox Code Playgroud)我通过添加定制器而不是自己创建连接工厂,将以下内容用于 Spring boot 2.6.4 + r2dbc-postgresql 0.8.11。
感谢 @Hantsy 指出 EnumCodec。我将其添加到定制器中,因此它可以与现有的自动配置过程很好地配合。另外,spring-data 不断将我的枚举转换为字符串,直到我添加转换器。
希望这些可以给其他人提供一点帮助。
将 EnumCodec 作为扩展注册到构建器定制器
可以注册多个枚举,只需重复 withEnum() 调用即可。
/**
* Use the customizer to add EnumCodec to R2DBC
*/
@Bean
public ConnectionFactoryOptionsBuilderCustomizer connectionFactoryOptionsBuilderCustomizer() {
return builder -> {
builder.option(Option.valueOf("extensions"),
List.of(EnumCodec.builder()
.withEnum("enum_foo", FooEnum.class)
.withRegistrationPriority(RegistrationPriority.FIRST)
.build()));
logger.info("Adding enum to R2DBC postgresql extensions: {}", builder);
};
}
Run Code Online (Sandbox Code Playgroud)
public class FooWritingConverter extends EnumWriteSupport<Foo> {
}
Run Code Online (Sandbox Code Playgroud)
注册转换器,以便 spring 数据不会总是将枚举转换为字符串。
这一步是 spring-boot-autoconfigure 项目中 R2dbcDataAutoConfiguration 的稍微增强版本。
/**
* Register converter to make sure Spring data treat enum correctly
*/
@Bean
public R2dbcCustomConversions r2dbcCustomConversions(DatabaseClient databaseClient) {
logger.info("Apply R2DBC custom conversions");
R2dbcDialect dialect = DialectResolver.getDialect(databaseClient.getConnectionFactory());
List<Object> converters = new ArrayList<>(dialect.getConverters());
converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);
return new R2dbcCustomConversions(
CustomConversions.StoreConversions.of(dialect.getSimpleTypeHolder(), converters),
List.of(
new FooWritingConverter()
));
}
Run Code Online (Sandbox Code Playgroud)
步骤 1 和 3 可以添加到您的应用程序类或任何其他有效配置中。