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

如何高效将JOOQ Records映射到Kotlin复杂领域模型

解决JOOQ多表查询映射到Kotlin嵌套数据类的问题

首先先修正你数据类的语法错误,否则无法编译:

data class Role(
    val id: String,
    val personId: String,
    val name: String,
    val description: String, // 补充类型声明
    val authorizations: List<Authorization> = emptyList() // 修正字段名和类型声明
)

你的原查询存在两个问题:一是没有关联AUTHORIZATION表,无法获取角色对应的权限数据;二是fetchOne()只能返回单条扁平记录,无法处理多表join后产生的重复分组数据。以下是完整的解决方案:

1. 修正查询语句

首先写出包含所有关联表的查询,获取完整的扁平结果集:

val records = mysqlDSLContext.select()
    .from(PERSON)
    .leftJoin(ROLE).on(PERSON.ID.eq(ROLE.PERSON_ID))
    .leftJoin(AUTHORIZATION).on(ROLE.ID.eq(AUTHORIZATION.ROLE_ID))
    .leftJoin(VEHICLE).on(PERSON.ID.eq(VEHICLE.PERSON_ID))
    .fetch()

2. 分组映射为嵌套数据类

由于多表join后,同一个Person会对应多条记录(每条记录对应一个Role或Authorization),我们需要通过分组聚合来构造嵌套结构:

val persons = records
    // 第一步:按Person ID分组,聚合同一个人的所有关联记录
    .groupBy { it[PERSON.ID] }
    .mapValues { (_, personRecords) ->
        val baseRecord = personRecords.first()
        // 构造Person基础信息
        val person = Person(
            id = baseRecord[PERSON.ID],
            name = baseRecord[PERSON.NAME],
            state = baseRecord[PERSON.STATE],
            // 构造Vehicle:假设一个人对应一辆车,取第一条非空的Vehicle记录
            vehicle = personRecords.firstNotNullOf {
                Vehicle(
                    id = it[VEHICLE.ID],
                    personId = it[VEHICLE.PERSON_ID],
                    name = it[VEHICLE.NAME],
                    type = it[VEHICLE.TYPE]
                )
            },
            // 构造Role列表:先按Role ID分组,聚合每个角色的权限
            roles = personRecords
                .filter { it[ROLE.ID] != null } // 过滤无角色的记录
                .groupBy { it[ROLE.ID] }
                .mapValues { (_, roleRecords) ->
                    val roleBase = roleRecords.first()
                    Role(
                        id = roleBase[ROLE.ID],
                        personId = roleBase[ROLE.PERSON_ID],
                        name = roleBase[ROLE.NAME],
                        description = roleBase[ROLE.DESCRIPTION],
                        // 构造当前角色的权限列表
                        authorizations = roleRecords
                            .filter { it[AUTHORIZATION.ID] != null }
                            .map {
                                Authorization(
                                    id = it[AUTHORIZATION.ID],
                                    roleId = it[AUTHORIZATION.ROLE_ID],
                                    type = it[AUTHORIZATION.TYPE]
                                )
                            }
                    )
                }
                .values
                .toList()
        )
        person
    }
    .values
    .toList()

3. 优化思路(通用方案)

如果需要复用这类嵌套映射逻辑,可以封装通用的分组工具函数,比如:

  • 提取mapToPerson、mapToRole等单独的映射函数
  • 针对一对多、一对一关系封装通用分组器,减少重复代码

这种手动分组的方式性能高效,逻辑清晰,完全基于JOOQ的基础API实现,不需要额外依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:26:21