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

如何自动将jOOQ记录映射到Java Records?附Sakila库示例

问题背景与需求

本文采用Sakila示例数据库,假设已定义如下Film类型的Java Record:

public record Film(UShort filmId, String title) {
}

从jOOQ读取影片数据时,可通过以下方式轻松映射到Film:

List<Film> films = this.context.select(Tables.FILM.FILM_ID, Tables.FILM.TITLE)
                               .from(Tables.FILM)
                               .limit(10)
                               .fetch(Records.mapping(Film::new));

若要查询影片及其关联演员,可使用multiset实现:

Set<SelectField<?>> readFields = Set.of(
    Tables.FILM.FILM_ID,
    Tables.FILM.TITLE,
    DSL.multiset(
        DSL.select(Tables.FILM_ACTOR.actor().FIRST_NAME, Tables.FILM_ACTOR.actor().LAST_NAME)
           .from(Tables.FILM_ACTOR)
           .where(Tables.FILM_ACTOR.FILM_ID.eq(Tables.FILM.FILM_ID))
        )
       .as("actors")
);

var result = this.context.select(readFields)
                         .from(Tables.FILM)
                         .limit(10)
                         .fetch();

现在希望将上述查询结果映射到如下FilmActors类型的Java Record:

public record FilmActors(UShort filmId, String title, List<Actor> actors) {
    public record Actor(String firstName, String lastName) {
    }
}

请问是否可自动完成该映射,或借助ModelMapper这类库实现?我希望尽量避免自定义RecordMapper。此前已尝试过jOOQ内置的Records类,并确认ModelMapper是否支持Records。


可行方案

一、jOOQ内置映射(无需自定义RecordMapper)

jOOQ的Records.mapping()支持嵌套映射,直接调整查询代码即可完成转换,无需额外依赖:

List<FilmActors> result = this.context.select(
        Tables.FILM.FILM_ID,
        Tables.FILM.TITLE,
        DSL.multiset(
            DSL.select(
                Tables.FILM_ACTOR.actor().FIRST_NAME,
                Tables.FILM_ACTOR.actor().LAST_NAME
            )
           .from(Tables.FILM_ACTOR)
           .where(Tables.FILM_ACTOR.FILM_ID.eq(Tables.FILM.FILM_ID))
        ).convertFrom(r -> r.map(Records.mapping(FilmActors.Actor::new)))
    )
   .from(Tables.FILM)
   .limit(10)
   .fetch(Records.mapping(FilmActors::new));

关键改动说明:

  • 对multiset的查询结果调用convertFrom(),通过Records.mapping(FilmActors.Actor::new)将内部记录批量转换为Actor列表
  • 外层直接用Records.mapping(FilmActors::new)完成整体映射,全程无需自定义RecordMapper

二、借助ModelMapper实现映射

ModelMapper 2.4.0及以上版本原生支持Java Record映射,步骤如下:

  1. 配置ModelMapper(字段名完全匹配时可省略显式映射):
ModelMapper modelMapper = new ModelMapper();
// 显式映射确保字段匹配准确
modelMapper.typeMap(Record3.class, FilmActors.class)
   .addMapping(r -> r.value1(), FilmActors::filmId)
   .addMapping(r -> r.value2(), FilmActors::title)
   .addMapping(r -> r.value3(), FilmActors::actors);

modelMapper.typeMap(Record2.class, FilmActors.Actor.class)
   .addMapping(r -> r.value1(), FilmActors.Actor::firstName)
   .addMapping(r -> r.value2(), FilmActors.Actor::lastName);
  1. 执行查询与映射:
var jooqResult = this.context.select(readFields)
                             .from(Tables.FILM)
                             .limit(10)
                             .fetch();

List<FilmActors> filmActorsList = jooqResult.stream()
    .map(record -> modelMapper.map(record, FilmActors.class))
    .collect(Collectors.toList());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:35:19