Как сохранить перечисление в виде строки в Hibernate 6 Spring Boot 3 без использования hibernate-types-62 в PostgreSQL

Со следующими компонентами базы данных postgresql и удалением аннотаций @Type и @Typedef в Spring Boot 3 (Hibernate 6), как мне сохранить перечисление как строку в базе данных, когда база данных также использует тип Enum для этого столбца.

Пример базы данных PG:

CREATE TYPE TEST_TYPE AS ENUM ('TESTA','TESTB');

CREATE TABLE test_table (
    id     INT           NOT NULL PRIMARY KEY,
    type   TEST_TYPE     NOT NULL
);

со следующей сущностью

@Entity
@Table(name = "test_table")
public class TestTableEntity
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Enumerated(EnumType.STRING)
    @Column(name = "type")
    private TestType tenantId;
}

Это не удается с ошибкой, потому что он пытается сохранить его как строку вместо типа перечисления.

Все остальные ресурсы ссылаются на библиотеку hypersistence-utils, hibernate-types-62. Однако мне не нужно зависеть от внешней библиотеки утилит.

Другие решения неуклюжи и требуют реализации новой иерархии только для перечислений.

Какое более простое решение для PostgreSQL?

1
0
172
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать ColumnTransformers для изменения SQL, сгенерированного Hibernate.

Это рабочий пример объекта:

@Entity
@Table(name = "test_table")
public class TestTableEntity
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Enumerated(EnumType.STRING)
    @Column(name = "type")
    @ColumnTransformer(write = "?::TEST_TYPE")
    private TestType tenantId;
}

Если это часть другой схемы, вам может потребоваться сделать

@ColumnTransformer(write = "?::other_table.TEST_TYPE")

Если вы проверите сгенерированный SQL, он будет использовать аннотацию @Enumerated для передачи TestType в виде строки. Затем ColumnTransformer добавит приведение для записи, позволяя запросу на вставку/обновление БД предоставить правильный тип параметра для предполагаемого столбца.

На обратном пути, поскольку @Enumerated настроен на использование String, Hibernate определит на основе сохраненной String, какой Enum выбрать и вернуть.

Это простой однострочный код, который не требует написания пользовательского типа UserType или использования библиотеки только для поддержки Enum.

Начиная с Hibernate 6.2, Hibernate по умолчанию использует типы enum в MySQL.

https://docs.jboss.org/hibernate/orm/6.2/migration-guide/migration-guide.html#ddl-implicit-datatype-enum

Например, этот код:

    public enum TestType {
        TESTA, TESTB
    }

    @Entity
    @Table(name = "test_table")
    public class TestTableEntity
    {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private int id;

        @Enumerated(EnumType.STRING)
        @Column(name = "type")
        private TestType tenantId;
    }

Создает следующий DDL:

    create table test_table (
        id integer not null auto_increment,
        type enum ('TESTA','TESTB'),
        primary key (id)
    ) engine=InnoDB

Так что тут ничего делать не надо, просто обновитесь до 6.2.

Однако это еще не реализовано для PostgreSQL, который, я думаю, вы используете (вы не указали). Проблема, которая предлагает добавить это:

https://hibernate.atlassian.net/browse/HHH-16125

Да! Спасибо, что назвали это, это будет хорошим дополнением для будущих читателей. Я добавлю уточнение конкретно для PostgreSQL.

StevenPG 20.04.2023 17:55

Другие вопросы по теме