How to persist an enum as string in Hibernate 6 Spring Boot 3 without using hibernate-types-62 in PostgreSQL

huangapple go评论66阅读模式
英文:

How to persist an enum as string in Hibernate 6 Spring Boot 3 without using hibernate-types-62 in PostgreSQL

问题

With the following PostgreSQL database components and the removal of the @Type and @Typedef annotations in Spring Boot 3 (Hibernate 6), how do I persist an enum as a String in the database when the database also uses an Enum type for that column?

PG数据库示例:

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

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

with the following Entity

@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;
}

This fails with an error because it attempts to persist it as a string instead of the enum type.

All other resources reference using the hypersistence-utils library, hibernate-types-62. However, I shouldn't need to be dependent on an external utils library.

The other solutions are clunky and require implementing a new hierarchy just for enums.

What is the simpler solution for PostgreSQL?

英文:

With the following postgresql database components and the removal of the @Type and @Typedef annotations in Spring Boot 3 (Hibernate 6), how do I persist an enum as a String in the database when the database also uses an Enum type for that column.

PG Database example:

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

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

with the following Entity

@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;
}

This fails with an error because it attempts to persist it as a string instead of the enum type.

All other resources reference using the hypersistence-utils library, hibernate-types-62. However, I shouldn't need to be dependent on an external utils library.

The other solutions are clunky and require implementing a new hierarchy just for enums.

What is the simpler solution for PostgreSQL?

答案1

得分: 4

你可以使用ColumnTransformers来修改Hibernate生成的SQL。

这是实体的一个示例:

@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将根据存储的字符串来确定选择和返回哪个枚举。

这是一个简单的一行代码,不需要编写自定义UserType或引入库来支持枚举。

英文:

You can use ColumnTransformers to alter the SQL generated by Hibernate.

This is a working example of the entity:

@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;
}

If it's part of a different schema, you may need to do

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

If you inspect the SQL that is generated, this will use the @Enumerated annotation to pass the TestType as a string. The ColumnTransformer will then add the cast in for writing, allowing the DB's insert/update query to provide the correct parameter type for the intended column.

On the way back out, since we have @Enumerated configured to use String, Hibernate will figure out based on the stored String, which Enum to select and return.

This is a simple one-liner that doesn't require writing a custom UserType or pulling in a library just to support Enums.

答案2

得分: 1

Since Hibernate 6.2, Hibernate uses enum types on MySQL by default.

例如,这段代码:

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

英文:

Since Hibernate 6.2, Hibernate uses enum types on MySQL by default.

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

For example, this code:

    public enum TestType {
		TESTA, TESTB
	}

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

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

Produces the following DDL:

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

So you don't have to do anything here, just upgrade to 6.2.

However, this is not yet implemented for PostgreSQL, which I guess is what you're using (you did not specify). The issue which proposes adding this is:

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

huangapple
  • 本文由 发表于 2023年4月19日 23:24:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056263.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定