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

如何在jOOQ中将左连接表映射为嵌套对象

问题

我想将两张表做左连接,然后映射到以下对象中,当没有关联元数据时,metadata对象应为null:

data class ObjectDto(
   val objectId: String,
   val name: String,
   val metadata: MetadataDto?
)

data class MetadataDto(
   val description: String,
   val comment: String
)

我尝试按照嵌套对象相关文档实现,但用下面的代码无法正确映射:

suspend fun getArrangements(objectIds: List<String>): List<ObjectDto> {
    return Flux.from(
        jooqDsl
            .select(
                OBJECT.OBJECT_ID,
                OBJECT.NAME,
                row(
                    METADATA.DESCRIPTION,
                    METADATA.COMMENT,

                ).mapping(::MetadataDto).`as`("METADATA")
            )
            .from(
                OBJECT.leftJoin(METADATA)
                    .on(OBJECT.OBJECT_ID.eq(METADATA.OBJECT_ID))
            )
            .where(OBJECT.OBJECT_ID.`in`(objectIds))
    )
        .map {
            it.into(ObjectDto::class.java)
        }
        .collectList()
        .awaitSingle()
}

执行查询后返回的数据是正确的,但metadata始终无法映射,一直为null,请问哪里出错了?

解决方案

问题主要出在默认反射映射无法识别自定义嵌套记录以及左连接空值未处理这两点:

  1. 你通过row(...).mapping().as("METADATA")定义的嵌套记录,无法被it.into(ObjectDto::class.java)的默认反射映射识别——jOOQ的默认into(Class)方法只会处理平级字段,不会关联你自定义的嵌套别名映射。
  2. 左连接无匹配记录时,METADATA的字段全为null,但直接用row(...)构造对象会生成一个全null字段的MetadataDto,而非你期望的null对象。

可以通过两种方式修正:

方法一:手动映射嵌套记录

在map阶段显式提取嵌套记录,判断空值后构造目标对象:

.map { record ->
    val metadataRecord = record.get("METADATA", Record::class.java)
    val metadata = if (metadataRecord?.value1() == null && metadataRecord?.value2() == null) {
        null
    } else {
        metadataRecord?.into(MetadataDto::class.java)
    }
    ObjectDto(
        objectId = record.get(OBJECT.OBJECT_ID),
        name = record.get(OBJECT.NAME),
        metadata = metadata
    )
}

方法二:在查询阶段直接构造目标对象

跳过中间嵌套记录的别名映射,直接在select或mapping阶段完成完整的对象构造,精准控制空值逻辑:

suspend fun getArrangements(objectIds: List<String>): List<ObjectDto> {
    return Flux.from(
        jooqDsl
            .select(OBJECT.OBJECT_ID, OBJECT.NAME, METADATA.DESCRIPTION, METADATA.COMMENT)
            .from(OBJECT.leftJoin(METADATA).on(OBJECT.OBJECT_ID.eq(METADATA.OBJECT_ID)))
            .where(OBJECT.OBJECT_ID.`in`(objectIds))
            .mapping { id, name, desc, comment ->
                ObjectDto(
                    objectId = id,
                    name = name,
                    metadata = if (desc == null && comment == null) null else MetadataDto(desc!!, comment!!)
                )
            }
    )
        .collectList()
        .awaitSingle()
}

内容的提问来源于stack exchange,提问作者m-kay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 19:15:38