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

Micronaut(Kotlin)中忽略自动生成ID转换请求DTO至@MappedEntity

解决Micronaut Kotlin中@MappedEntity自动生成主键的DTO转换问题

针对你遇到的主键字段必填导致转换函数编译失败的问题,这里提供几种实用的原生解决方案,无需额外引入依赖:


方法1:将主键字段设为可空并赋予默认值

这是最简洁的方案,因为@GeneratedValue标记的主键由数据库自动生成,插入时无需我们提供值。在Kotlin数据类中把purchaseId设为可空类型并赋予默认值null,创建实体时就可以跳过该字段:

import io.micronaut.data.annotation.GeneratedValue
import io.micronaut.data.annotation.Id
import io.micronaut.data.annotation.MappedEntity

@MappedEntity
data class PurchasedDataEntity(
    @Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    val purchaseId: Long? = null, // 可空类型+默认值null
    val productName: String,
    val quantity: Int
    // 其他业务字段
)

转换函数可以直接忽略主键字段:

fun PurchaseRequestDto.toPurchasedDataEntity(): PurchasedDataEntity {
    return PurchasedDataEntity(
        productName = this.productName,
        quantity = this.quantity
        // 无需传递purchaseId,自动使用默认值null
    )
}

调用repository.save()时,Micronaut Data会自动识别该字段为数据库生成,不会将null插入数据库,而是由PostgreSQL生成主键值。


方法2:添加次级构造函数

如果不想修改主键字段的可空性,可以给实体类添加一个不带主键参数的次级构造函数,用临时值占位(插入时会被数据库覆盖):

@MappedEntity
data class PurchasedDataEntity(
    @Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    val purchaseId: Long,
    val productName: String,
    val quantity: Int
) {
    // 次级构造函数,无需传入purchaseId
    constructor(productName: String, quantity: Int) : this(
        purchaseId = 0, // 临时占位值,不影响数据库生成主键
        productName = productName,
        quantity = quantity
    )
}

转换函数直接调用次级构造函数:

fun PurchaseRequestDto.toPurchasedDataEntity(): PurchasedDataEntity {
    return PurchasedDataEntity(
        productName = this.productName,
        quantity = this.quantity
    )
}

方法3:使用Kotlin no-arg插件

如果你的项目允许配置插件,可以启用Kotlin的no-arg插件,让Micronaut Data能通过无参构造函数创建实体对象,再逐个设置字段:

首先在build.gradle.kts中配置插件:

plugins {
    kotlin("plugin.noarg") version "你的Kotlin版本号"
}

noArg {
    annotation("io.micronaut.data.annotation.MappedEntity")
}

实体类保持主键非空:

@MappedEntity
data class PurchasedDataEntity(
    @Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    val purchaseId: Long,
    val productName: String,
    val quantity: Int
)

转换函数用apply方法赋值:

fun PurchaseRequestDto.toPurchasedDataEntity(): PurchasedDataEntity {
    return PurchasedDataEntity().apply {
        productName = this@toPurchasedDataEntity.productName
        quantity = this@toPurchasedDataEntity.quantity
    }
}

推荐优先使用方法1,它最符合Kotlin和Micronaut Data的设计逻辑,代码简洁且无额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:35:17