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

如何在JOOQ中将表字段映射转换为自定义ENUM类型?

JOOQ 枚举类型转换失败的解决方法

问题背景

使用JOOQ时遇到表字段无法转换为自定义ENUM类型的问题,尝试多种转换方法均无效或报错,配置JOOQ Codegen操作失败,未找到明确操作文档。

查询代码

return new PageImpl<>(DSL.select(field("kk.id"),
                        field("kk.epk_id"),
                        field("kk.uir"),
                        field("kk.status_code", VARCHAR.asEnumDataType(StatusCode.class)), // 此行未实现预期的枚举转换
                        field("kk.end_date", DATE),
                        field("kk.sudir_user_name"),
                        field("val.name_kk")).
                from("ccl_test.calculation_kk kk" +
                        "join ccl_test.values_kk val" +
                        "on (case resulting_calculation_value" +
                        "    when 'value_ml_model' then id_ml_model_value=val.id" +
                        "    when 'value_lm' then id_lm_value=val.id" +
                        "    when 'value_verifier' then id_verifier_value=val.id" +
                        "    END)" +
                        "where status_code='completed'")
                .orderBy(field("kk.id"))
                .limit(pageable.getPageSize())
                .offset(pageable.getOffset())
                .fetchInto(CalculationDTOForAll.class));

ENUM定义

public enum StatusCode {
    INITIATED("initiated","Инициирован"),
    ON_VERIFICATION("for_verification","На верификации"),
    ON_CONFIRMATION("confirmation","На подтверждении"),
    COMPLETED("completed","Завершен");
    private final String value;
    private final String codeName;

    StatusCode(String value, String codeName) {
        this.value = value;
        this.codeName = codeName;
    }

    public String getValue() {
        return value;
    }

    public String getCodeName() {
        return codeName;
    }
}

DTO类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CalculationDTOForAll {
    private Long        id;
    private Long        epkId;
    private String      uir;
    private StatusCode  statusCode; // 此处ENUM未完成转换
    @JsonFormat(pattern = "dd.MM.yy HH:mm:ss")
    private Date        endDate;
    private String      sudirUserName;
    private String      nameKk;
}

问题原因

JOOQ默认使用枚举的name()(枚举常量名,如COMPLETED)或ordinal()进行转换,但你的枚举依赖自定义value字段存储数据库值,默认转换逻辑不匹配。


解决方法

方法1:给枚举添加静态转换方法

在StatusCode枚举中添加静态方法,根据数据库字符串值匹配枚举实例:

public enum StatusCode {
    // 原有枚举常量、构造方法及getter
    
    public static StatusCode fromValue(String value) {
        for (StatusCode status : values()) {
            if (status.value.equals(value)) {
                return status;
            }
        }
        throw new IllegalArgumentException("无效状态码:" + value);
    }
}

修改查询中的字段转换逻辑,手动指定转换器:

field("kk.status_code", 
      Converter.of(String.class, StatusCode.class, 
                   StatusCode::fromValue, 
                   StatusCode::getValue))

方法2:全局注册枚举转换器

若多处需要使用该枚举转换,可全局配置JOOQ的Configuration:

  1. 实现Converter接口:
public class StatusCodeConverter implements Converter<String, StatusCode> {
    @Override
    public StatusCode from(String databaseObject) {
        return StatusCode.fromValue(databaseObject);
    }

    @Override
    public String to(StatusCode userObject) {
        return userObject.getValue();
    }

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

    @Override
    public Class<StatusCode> toType() {
        return StatusCode.class;
    }
}
  1. 在JOOQ配置中注册转换器:
Configuration configuration = new DefaultConfiguration()
    .set(SQLDialect.MYSQL) // 替换为你的数据库方言
    .set(new DefaultDataTypeProvider() {
        @Override
        public <T> DataType<T> defaultDataType(Class<T> type) {
            if (type == StatusCode.class) {
                return (DataType<T>) SQLDataType.VARCHAR.asConvertedDataType(new StatusCodeConverter());
            }
            return super.defaultDataType(type);
        }
    });

之后查询可直接使用field("kk.status_code", StatusCode.class),JOOQ会自动应用转换器。

方法3:配置JOOQ Codegen自动生成枚举映射

通过Codegen自动绑定枚举与数据库字段:

  1. 在jooq-codegen.xml(或Maven/Gradle配置)中添加强制类型映射:
<configuration>
    <generator>
        <database>
            <forcedTypes>
                <forcedType>
                    <userType>com.yourpackage.StatusCode</userType>
                    <converter>com.yourpackage.StatusCodeConverter</converter>
                    <includeExpression>STATUS_CODE</includeExpression> <!-- 匹配数据库字段名 -->
                    <includeTypes>VARCHAR</includeTypes>
                </forcedType>
            </forcedTypes>
        </database>
    </generator>
</configuration>
  1. 执行Codegen后,生成的表字段会自动关联StatusCode枚举,查询时直接使用生成字段即可。

内容的提问来源于stack exchange,提问作者Будь как Я

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:55:03