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

Micronaut Data JDBC:如何用枚举映射单向一对多关系?

Micronaut Data 实现用户-角色单向一对多关系映射

需求说明

通过Micronaut Data注解,将给定的Kotlin对象模型(User包含Set<Role>)映射为单向一对多关系,可调整数据库模型以适配对象模型。

给定对象模型

import io.micronaut.serde.annotation.Serdeable

@Serdeable
enum class Role {
    Admin, Manager
}
import io.micronaut.data.annotation.GeneratedValue
import io.micronaut.data.annotation.Id
import io.micronaut.data.annotation.MappedEntity
import io.micronaut.serde.annotation.Serdeable

@Serdeable
@MappedEntity
data class User(

    @field:Id
    @field:GeneratedValue
    var id: Long? = null,
    
    val username: String,

    // 需要映射的角色集合
    var roles: Set<Role>? = null
)

方案一:基于原多对多数据库模型适配

修改后的数据库DDL

调整原多对多模型,确保关联表的完整性,适配单向一对多映射逻辑:

CREATE TABLE "user"
(
    id       SERIAL PRIMARY KEY,
    username VARCHAR(30) NOT NULL UNIQUE
);

CREATE TABLE "role"
(
    id INTEGER PRIMARY KEY,
    name VARCHAR(40) NOT NULL UNIQUE
);

CREATE TABLE "user_role"
(
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES "user" (id),
    role_id INTEGER NOT NULL REFERENCES "role" (id),
    CONSTRAINT user_role_unique UNIQUE (user_id, role_id)
);

INSERT INTO "role" (id, name) VALUES (1, 'Admin'), (2, 'Manager');

映射后的User实体代码

通过Micronaut Data的@Relation和@JoinTable注解实现单向一对多映射:

import io.micronaut.data.annotation.*
import io.micronaut.serde.annotation.Serdeable
import jakarta.persistence.Enumerated
import jakarta.persistence.EnumType

@Serdeable
@MappedEntity
data class User(

    @field:Id
    @field:GeneratedValue
    var id: Long? = null,
    
    val username: String,

    // 单向一对多映射配置
    @field:Relation(Relation.Kind.ONE_TO_MANY)
    @field:JoinTable(
        name = "user_role",
        joinColumns = [JoinColumn(name = "user_id")],
        inverseJoinColumns = [JoinColumn(name = "role_id", referencedColumnName = "id")]
    )
    @field:Enumerated(EnumType.STRING)
    var roles: Set<Role>? = null
)

注解说明:

  • @Relation(Relation.Kind.ONE_TO_MANY):声明该字段为单向一对多关系
  • @JoinTable:指定关联中间表的名称及字段映射,joinColumns关联当前实体(User)的主键,inverseJoinColumns关联Role表的主键
  • @Enumerated(EnumType.STRING):将枚举类型映射为数据库中的字符串值,与role表的name字段对应

方案二:使用PostgreSQL枚举类型简化模型

利用PostgreSQL原生枚举类型,省去独立的role表,直接在关联表中存储枚举值,更贴合对象模型:

修改后的数据库DDL

CREATE TABLE "user"
(
    id       SERIAL PRIMARY KEY,
    username VARCHAR(30) NOT NULL UNIQUE
);

-- 创建与Kotlin枚举完全对应的PostgreSQL枚举类型
CREATE TYPE role_name AS ENUM ('Admin', 'Manager');

CREATE TABLE "user_role"
(
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES "user" (id),
    role role_name NOT NULL,
    CONSTRAINT user_role_unique UNIQUE (user_id, role)
);

映射后的User实体代码

import io.micronaut.data.annotation.*
import io.micronaut.serde.annotation.Serdeable
import jakarta.persistence.Enumerated
import jakarta.persistence.EnumType

@Serdeable
@MappedEntity
data class User(

    @field:Id
    @field:GeneratedValue
    var id: Long? = null,
    
    val username: String,

    // 单向一对多映射配置
    @field:Relation(Relation.Kind.ONE_TO_MANY)
    @field:JoinColumn(name = "user_id")
    @field:Column(name = "role")
    @field:Enumerated(EnumType.STRING)
    var roles: Set<Role>? = null
)

注解说明:

  • @Relation(Relation.Kind.ONE_TO_MANY):声明单向一对多关系
  • @JoinColumn(name = "user_id"):指定关联表中对应用户主键的外键字段
  • @Column(name = "role"):指定关联表中存储枚举值的字段
  • @Enumerated(EnumType.STRING):确保枚举与PostgreSQL枚举类型的字符串值匹配

额外配置

为让Micronaut Data正确识别PostgreSQL枚举类型,需在application.yml中添加方言配置:

jpa:
  properties:
    hibernate:
      dialect: org.hibernate.dialect.PostgreSQLDialect

内容的提问来源于stack exchange,提问作者Alexandre V.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:10:47