如何通过jOOQ生成器将数据库表、列名映射为易读名称?
我有一个遗留数据库,表和列名如下:
XYZEMP:
- XYZCMP
- XYZUSR
- XYZNME
希望映射为易读名称:
EMPLOYEE:
- COMPANY
- USERNAME
- NAME
使用标准jOOQ代码生成器时,会生成XYZEMP表对象、XyzempRecord等,列名仍为XYZCMP这类缩写,对应的getter/setter也沿用原名称。请问能否通过传递映射规则给生成器,让它生成Employee表对象、EmployeeRecord以及易读的列名?
我的思路是使用自定义生成器策略,示例代码如下:
public class AsInDatabaseStrategy extends DefaultGeneratorStrategy { @Override public String getJavaClassName(Definition definition, Mode mode) { Map<String, String> tableNamesMapping = readTableNames(); if (mode == Mode.DEFAULT){ //for table class String readableName = tableNamesMapping.get(definition.getOutputName()); if (readableName == null){ throw new IllegalStateException("Table " + definition.getOutputName() + " lacks mapping"); } return readableName; } else if (mode == Mode.RECORD) { // for record // similar logic for record return readableName + "Record"; } return super.getJavaClassName(definition, mode); } @Override public String getJavaIdentifier(Definition definition) { // somehow similar code for table and and column } @Override public String getJavaSetterName(Definition definition, Mode mode) { // somehow similar code for table and and column } @Override public String getJavaGetterName(Definition definition, Mode mode) { // somehow similar code for table and and column } private Map<String, String> readTableNames(){ //read names mapping from file } private Map<String, Map<String, String>> readColumnNames(){ //read names mapping from file } }
映射文件分为表映射:
{ "XYZEMP" : "EMPLOYEE", ... }
和列映射:
{ "XYZEMP" : { "XYZCMP" : "COMPANY", "XYZUSR" : "USERNAME", "XYZNME" : "NAME" } ... }
请问有没有更优的实现方式?另外在我的方案中,如何通过Definition对象区分表/列(或其他对象),以及如何获取列所属的表?
1. 更优实现方式
你的自定义生成器策略思路是可行的,以下是几个优化方向:
(1)复用内置策略逻辑
不用完全重写所有方法,DefaultGeneratorStrategy已经提供了驼峰转换等命名规范处理逻辑,可以在映射后的名称基础上调用父类方法做规范处理。比如映射得到EMPLOYEE后,父类会自动转成Employee作为类名,避免手动处理大小写。
(2)使用配置式映射(无需编写自定义类)
jOOQ 3.14+支持在代码生成XML配置中直接定义映射规则,无需编写自定义Java类,维护成本更低,适合规则固定的场景:
<generator> <database> <name>org.jooq.meta.postgres.PostgresDatabase</name> <!-- 表名与记录类名映射 --> <tables> <table> <inputName>XYZEMP</inputName> <outputName>EMPLOYEE</outputName> <recordName>EmployeeRecord</recordName> <!-- 列名映射 --> <fields> <field> <inputName>XYZCMP</inputName> <outputName>COMPANY</outputName> </field> <field> <inputName>XYZUSR</inputName> <outputName>USERNAME</outputName> </field> <field> <inputName>XYZNME</inputName> <outputName>NAME</outputName> </field> </fields> </table> </tables> </database> </generator>
如果映射规则需要动态加载(比如从外部配置文件读取),再使用自定义策略方案更合适。
(3)缓存映射规则
你的readTableNames()和readColumnNames()方法每次调用都会读取文件,建议在策略类初始化时一次性加载并缓存映射规则,避免重复IO操作。
2. 区分Definition类型与获取列所属表
(1)区分表/列等对象类型
Definition是所有数据库对象的父接口,可以通过instanceof判断具体类型:
// 判断是否为表 if (definition instanceof TableDefinition) { // 处理表逻辑 } // 判断是否为列 else if (definition instanceof ColumnDefinition) { // 处理列逻辑 } // 其他类型(如索引、约束)可类似判断 else if (definition instanceof IndexDefinition) { // 处理索引逻辑 }
(2)获取列所属的表
ColumnDefinition提供了getTable()方法,可直接获取所属表的TableDefinition:
if (definition instanceof ColumnDefinition colDef) { TableDefinition tableDef = colDef.getTable(); String originalTableName = tableDef.getOutputName(); // 获取原表名,用于查找列映射 }
内容的提问来源于stack exchange,提问作者Loginus

