英文:
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 = "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;
}
Produces the following DDL:
create table test_table (
id integer not null auto_increment,
type enum ('TESTA','TESTB'),
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论