You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Hibernate中实现Kotlin枚举与PostgreSQL枚举的映射?

解决Kotlin枚举与PostgreSQL枚举的Hibernate映射问题

你遇到的错误核心原因是:Hibernate通过@Enumerated(EnumType.STRING)将Kotlin枚举转换为普通字符串类型,但PostgreSQL的default_calculation_method列是自定义枚举类型,两者类型不兼容,导致数据库抛出类型不匹配错误。以下是几种可行的解决方式:


方法一:使用第三方Hibernate类型库(推荐)

借助hibernate-types库提供的PostgreSQLEnumType,可以直接映射PostgreSQL自定义枚举类型,无需手动编写转换器。

1. 添加依赖

根据你的Hibernate版本选择对应库版本(示例针对Hibernate 5.5+):

// Gradle
implementation("com.vladmihalcea:hibernate-types-55:2.20.0")

// Maven
<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-55</artifactId>
    <version>2.20.0</version>
</dependency>

2. 修改实体类

通过@TypeDef注册枚举类型,再用@Type指定字段使用该类型:

import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef

@TypeDef(
    name = "pgsql_enum",
    typeClass = PostgreSQLEnumType::class
)
@Entity
@Table(name = "component_type")
class ComponentTypeEntity (
    @Enumerated(EnumType.STRING)
    @Type(type = "pgsql_enum")
    var defaultCalculationMethod: CalculationMethod?,

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null
)

方法二:自定义Hibernate枚举转换器(无第三方依赖)

如果不想引入外部库,可以实现Hibernate的UserType接口,手动处理枚举与PostgreSQL自定义类型的转换。

1. 编写自定义类型类

import org.hibernate.HibernateException
import org.hibernate.engine.spi.SharedSessionContractImplementor
import org.hibernate.usertype.UserType
import java.io.Serializable
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Types

class PostgreSqlEnumUserType<T : Enum<T>> : UserType {
    private lateinit var enumType: Class<T>

    override fun returnedClass(): Class<*> = enumType

    override fun equals(x: Any?, y: Any?): Boolean = x == y

    override fun hashCode(x: Any?): Int = x?.hashCode() ?: 0

    override fun nullSafeGet(
        rs: ResultSet,
        names: Array<out String>,
        session: SharedSessionContractImplementor,
        owner: Any?
    ): Any? {
        val value = rs.getString(names[0])
        return if (value != null && !rs.wasNull()) {
            Enum.valueOf(enumType, value)
        } else null
    }

    override fun nullSafeSet(
        st: PreparedStatement,
        value: Any?,
        index: Int,
        session: SharedSessionContractImplementor
    ) {
        if (value == null) {
            st.setNull(index, Types.OTHER)
        } else {
            st.setObject(index, value.toString(), Types.OTHER)
        }
    }

    override fun deepCopy(value: Any?): Any? = value

    override fun isMutable(): Boolean = false

    override fun disassemble(value: Any?): Serializable? = value as? Serializable

    override fun assemble(cached: Serializable?, owner: Any?): Any? = cached

    override fun replace(original: Any?, target: Any?, owner: Any?): Any? = original

    @Suppress("UNCHECKED_CAST")
    override fun setParameterValues(params: MutableMap<String, Any>?) {
        enumType = params?.get("enumClass") as Class<T>
    }
}

2. 配置实体类使用自定义类型

import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef

@TypeDef(
    name = "postgre_sql_enum",
    typeClass = PostgreSqlEnumUserType::class,
    parameters = [org.hibernate.annotations.Parameter(
        name = "enumClass",
        value = "com.yourpackage.CalculationMethod" // 替换为你的枚举类全路径
    )]
)
@Entity
@Table(name = "component_type")
class ComponentTypeEntity (
    @Enumerated(EnumType.STRING)
    @Type(type = "postgre_sql_enum")
    var defaultCalculationMethod: CalculationMethod?,

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null
)

方法三:Spring Boot+Hibernate 6.x 简化配置

如果使用Hibernate 6.x及以上版本,可通过配置直接兼容PostgreSQL枚举,无需额外代码:

  1. 在application.properties中添加配置:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.url=jdbc:postgresql://localhost:5432/your_db?stringtype=unspecified
  1. 实体类保留@Enumerated(EnumType.STRING)即可,无需额外注解:
@Entity
@Table(name = "component_type")
class ComponentTypeEntity (
    @Enumerated(EnumType.STRING)
    var defaultCalculationMethod: CalculationMethod?,

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null
)

注意事项

  • 确保PostgreSQL驱动版本≥42.2.0,避免类型兼容问题
  • Kotlin枚举的枚举值名称需与数据库中自定义枚举的大小写完全一致(你的示例中FIXED、TIERED匹配,无需修改)

内容的提问来源于stack exchange,提问作者Shaimaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 22:45:58