как использовать EnumCodec в r2dbc-postgresql

Я безуспешно пытаюсь использовать EnumCodec из последней версии r2dbc-postgresql (0.8.4), и мне было интересно, можете ли вы мне помочь.

Я также использую spring-data-r2dbc версии 1.1.1.

Я взял точный пример из GitHub и создал тип перечисления «my_enum» в моем Postgres и таблицу «sample_table», которая содержит «name» (текст) и «value» (my_enum).

Затем я сделал как в примере:

SQL:

CREATE TYPE my_enum AS ENUM ('FIRST', 'SECOND');

Модель Java:

enum MyEnumType {
  FIRST, SECOND;
}

Регистрация кодека:

PostgresqlConnectionConfiguration.builder()
.codecRegistrar(EnumCodec.builder().withEnum("my_enum", MyEnumType.class).build());

Я использую DatabaseClient для связи с БД. Пробовал вставлять двумя способами:

databaseClient.insert().into(SampleTable.class)
.using(sampleTable).fetch().rowsUpdated();

or:

databaseClient.insert().into("sample_table")
.value("name", sampleTable.getName())
.value("value", sampleTable.getValue())
.then();

где SampleTable:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table("sample_table")
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SampleTable implements Serializable {
   private String name;
   @Column("value")
   @JsonProperty("value")
   private MyEnumType value;
}

Но я получаю ту же ошибку, используя оба:

значение столбца имеет тип my_enum, а выражение - переменный символ

Не могли бы вы помочь мне понять, что я сделал не так, или посоветовать мне какой-нибудь рабочий пример? Я ценю вашу помощь!


person eladya    schedule 22.07.2020    source источник


Ответы (2)


Spring Data рассматривает значения перечисления как значения, которые по умолчанию должны быть преобразованы в String. Вам необходимо зарегистрировать Converter, который сохраняет тип, записав enum-type как есть.

@WritingConverter
class MyEnumTypeConverter implements Converter<MyEnumType, MyEnumType> {
    @Override
    public MyEnumType convert(MyEnumType source) {
        return source;
    }
}

Далее вам необходимо зарегистрировать конвертер. Если вы используете Spring Data R2DBC AbstractR2dbcConfiguration, переопределите getCustomConverters():

class MyConfiguration extends AbstractR2dbcConfiguration {

    @Override
    protected List<Object> getCustomConverters() {
        return Collections.singletonList(new MyEnumTypeConverter());
    }

  // …
}

В качестве альтернативы, если вы настраиваете DatabaseClient автономно, вам понадобится немного больше кода:

PostgresqlConnectionConfiguration configuration = PostgresqlConnectionConfiguration.builder()
        .codecRegistrar(EnumCodec.builder().withEnum("my_enum", MyEnumType.class).build())
        .host(…)
        .username(…)
        .password(…)
        .database(…).build();

R2dbcDialect dialect = PostgresDialect.INSTANCE;
DefaultReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(dialect, Collections.singletonList(new MyEnumTypeConverter()));

DatabaseClient databaseClient = DatabaseClient.builder()
        .connectionFactory(new PostgresqlConnectionFactory(configuration))
        .dataAccessStrategy(strategy)
        .build();
    

Однако в драйвере R2DBC есть две ошибки, которые не позволяют Spring Data работать должным образом:

В качестве временного решения вы можете продублировать EnumCodec в своей кодовой базе и применять исправление с #302, пока не будет доступна новая версия R2DBC Postgres.

person mp911de    schedule 22.07.2020
comment
Спасибо! Кажется, он работает, но я не могу прочитать данные, записанные при использовании databaseClient.select () - я получаю сообщение «Не удалось прочитать свойство из-за ошибки набора результатов». Как правильно написать ReadingConverter? - person eladya; 23.07.2020
comment
См. Приведенные выше ссылки на ошибки, приводящие к сбою чтения строк. - person mp911de; 23.07.2020
comment
Я выполнил указанные выше действия и попытался продублировать EnumCodec, но у меня возникла следующая ошибка: Caused by: java.lang.IllegalArgumentException: 16404 is not a valid object id at io.r2dbc.postgresql.type.PostgresqlObjectId.valueOf(PostgresqlObjectId.java:417) at io.r2dbc.postgresql.codec.AbstractTemporalCodec.canDecode(AbstractTemporalCodec.java:69) - person shaun_abitbol; 27.07.2020

Я пробовал использовать тип pg enum и класс Java Enum в своих примерах проектов.

  1. Если вы используете DatabaseClient API (в ядре Spring 5.3 не используйте Spring Data R2dbc), достаточно зарегистрировать EnumCodec в PostgresConnectionFactory.

    Проверьте мой пример.

  2. При создании перечисления типа pg в качестве типа столбца в схеме таблицы и зарегистрируйте EnumCodec в PostgresConnectionFactory.builder. Вам нужно написать custom @ReadingConverter, чтобы прочитать настраиваемое перечисление.

    Посмотрите мой пример здесь.

  3. Если вы используете текстовый тип (varchar) в схеме таблицы с Java Enum. нет необходимости прилагать дополнительные усилия для преобразования, проверьте мой пример здесь.

В Spring Data R2dbc сказано, что при использовании встроенного механизма драйвера для обработки перечисления вы должны зарегистрировать EnumWriteSupport. Но согласно моему опыту, при использовании Spring Data R2dbc запись может выполняться автоматически, но для чтения enum из Postgres требуется преобразователь чтения.

person Hantsy    schedule 13.09.2020