如何在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:
- 实现
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; } }
- 在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自动绑定枚举与数据库字段:
- 在
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>
- 执行Codegen后,生成的表字段会自动关联
StatusCode枚举,查询时直接使用生成字段即可。
内容的提问来源于stack exchange,提问作者Будь как Я
相关产品推荐
相关产品推荐

