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

如何通过Lateral Join与arrayAgg()将Long[]字段映射至POJO?

如何用Lateral Join结合arrayAgg()将Long[]字段映射到自定义POJO?

问题代码示例

查询方法:

public Optional<TeacherWithStudents> getTeachersWithStudentsForStudentId(long studentId) {
  return ctx().select(
                TEACHER.ID,
                TEACHER.NAME,
                DSL.field("student.ids", STUDENT_TEACHER_MAPPING.STUDENT_ID.getDataType().getArrayType()))
        .from(TEACHER)
        .leftJoin(DSL.lateral(
                DSL.select(DSL.arrayAgg(STUDENT_TEACHER_MAPPING.STUDENT_ID).as("ids"))
                        .from(STUDENT_TEACHER_MAPPING)
                        .where(STUDENT_TEACHER_MAPPING.TEACHER_ID.eq(TEACHER.ID))).as("student"))
        .on(DSL.condition(true))
        .limit(1)
        .fetchOptionalInto(TeacherWithStudents.class);
}

POJO类:

@Data
@AllArgsConstructor
public class TeacherWithStudents {
  long id;
  String name;
  Long[] ids;
}

已尝试的方案

  • 向DSL.field传入Long[].class,映射到jOOQ Record有效,但无法映射到POJO,报错:org.jooq.exception.MappingException: An error occurred when mapping record to class [Ljava.lang.Long;
  • 用DSL.jsonArrayAgg替代arrayAgg,结果得到仅含一个null值的数组[null]
  • 使用multiset可行,但需重复关联子查询以满足WHERE条件,不够优雅
  • 尝试多种自定义转换器均未生效
  • 先获取Record再用Jackson转POJO,可行但效率低下

解决方法

方案1:调整POJO映射规则并明确字段类型

jOOQ对数组类型的POJO映射更适配无参构造器+Setter模式,同时需确保字段类型与SQL数组严格匹配:

  1. 修改POJO,显式添加无参构造器(配合Lombok注解):
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TeacherWithStudents {
  long id;
  String name;
  Long[] ids;
}
  1. 查询中使用jOOQ原生的数组DataType,避免直接传入Long[].class:
DataType<Long[]> longArrayType = STUDENT_TEACHER_MAPPING.STUDENT_ID.getDataType().getArrayType();

return ctx().select(
                TEACHER.ID,
                TEACHER.NAME,
                DSL.field("student.ids", longArrayType))
        // 其余查询逻辑不变
        .fetchOptionalInto(TeacherWithStudents.class);

方案2:自定义数组类型Converter

如果默认转换逻辑不兼容数据库数组实现,可自定义Converter处理SQL数组到Java Long[]的转换:

  1. 实现jOOQ的Converter接口(以PostgreSQL为例):
public class SqlArrayToLongArrayConverter implements Converter<Object, Long[]> {
    @Override
    public Long[] from(Object databaseObject) {
        if (databaseObject == null) return new Long[0];
        if (databaseObject instanceof PGArray) {
            try {
                return (Long[]) ((PGArray) databaseObject).getArray();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        return (Long[]) databaseObject;
    }

    @Override
    public Object to(Long[] userObject) {
        return userObject;
    }

    @Override
    public Class<Object> fromType() {
        return Object.class;
    }

    @Override
    public Class<Long[]> toType() {
        return Long[].class;
    }
}
  1. 在查询中绑定该Converter:
DataType<Long[]> longArrayType = SQLDataType.BIGINT.getArrayDataType().converter(new SqlArrayToLongArrayConverter());

return ctx().select(
                TEACHER.ID,
                TEACHER.NAME,
                DSL.field("student.ids", longArrayType))
        // 其余查询逻辑不变
        .fetchOptionalInto(TeacherWithStudents.class);

方案3:用RecordMapper手动映射(高效灵活)

如果上述方案仍不生效,可直接通过Record手动映射,避免POJO自动映射的兼容性问题:

return ctx().select(
                TEACHER.ID,
                TEACHER.NAME,
                DSL.field("student.ids", STUDENT_TEACHER_MAPPING.STUDENT_ID.getDataType().getArrayType()))
        // 其余查询逻辑不变
        .fetchOptional(record -> new TeacherWithStudents(
                record.get(TEACHER.ID),
                record.get(TEACHER.NAME),
                record.get(DSL.field("student.ids", Long[].class))
        ));

内容的提问来源于stack exchange,提问作者torta-frita

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:31:04