Skip to content

10 · 元数据驱动的动态写入/读取(persist-meta 规范)

版本:1.8.0(起,1.8.0 同步演进) 定位:字段元数据(storageType)驱动的执行规范——复杂字段插入(对象/JSON/子表) 与流程回显读取成为通用能力,不再绑定任何框架的低代码设施。 与 DynamicTableWriter(spec 09)的关系:演进而非推翻——现有 SPI 保留,无元数据回落现状。

1. 目标与边界

做(最小闭环)

  • 字段元数据(storageType)驱动的动态写入(NORMAL/EXPAND/JSON/ONE2ONE/ONE2MANY)
  • 按流程实例的动态读取回显readByProcessInstance,与写入共用同一份元数据)
  • 元数据来源可插拔(SPI),内置 JSON 配置加载器(零依赖)

不做(明确边界)

通用条件分页 / 动态条件语法(m_EQ_xxx)/ 数据权限 / 排序——集成方查询体系(如 mldong tablePage) 的领域,双方共享字段元数据规范保持语义一致。

2. 元数据模型(四语言契约)

2.1 JSON 配置字段语义(persist-meta/biz_leave.json,文件名=表名)

顶层:

字段类型缺省语义
tableNamestring必填业务表名(应与此 JSON 文件名一致)
primaryKeystringid主键列名(ONE2ONE/ONE2MANY 子表外键缺省回落它)
fieldsarray必填字段定义列表(见下)

fields[] 元素:

字段类型缺省语义
namestring必填表单字段名(实例 Variables 中 f_ 去前缀后的名字,如 f_titletitle
columnNamestringname 转下划线主表列名(如 companyNamecompany_name
storageTypestring | numberNORMAL存储类型——名称或数字双解析(见下表)
expandFieldsobjectEXPAND 专用:子字段名 → 表列名映射({ "province": "province", "detail": "detail_addr" }
targetTablestringONE2ONE/ONE2MANY 专用:子表表名
foreignKeystring主表 primaryKey 列名ONE2ONE/ONE2MANY 专用:子表外键列

storageType 取值(对齐 mldong dev_schema_field 1-5,名称/数字双解析):

名称语义
1NORMAL直写列(默认)
2EXPAND对象展开为多列(expandFields 定义子字段列映射)
3JSON对象/数组序列化为 JSON 串写列
4ONE2ONE子表单条递归插入(外键 = 主表主键,同事务)
5ONE2MANY子表多条递归插入(data 值为数组,同事务)

JSON 配置示例(persist-meta/biz_leave.json):

json
{
  "tableName": "biz_leave",
  "primaryKey": "id",
  "fields": [
    { "name": "companyName", "columnName": "company_name", "storageType": "NORMAL" },
    { "name": "address", "storageType": "EXPAND",
      "expandFields": { "province": "province", "city": "city", "detail": "detail_addr" } },
    { "name": "extra", "storageType": "JSON" },
    { "name": "items", "storageType": "ONE2MANY",
      "targetTable": "biz_leave_item", "foreignKey": "leave_id" }
  ]
}

3. SPI(集成方只实现一件事:提供元数据)

java
public interface IDynamicMetaProvider {
    /** 加载表元数据;未定义返回 null(回落表结构探测,全 NORMAL 语义) */
    TableMeta loadTableMeta(String tableName);
}
  • 内置 JsonMetaProvider:从文件系统/classpath 加载 persist-meta/*.json
  • 写、读共用:写入引擎与回显读取都按同一份元数据执行,storageType 语义两侧一致
  • 默认回落:未配元数据时行为与 1.6.x 完全一致(零破坏)

4. 组件分工(读写职责分离)

写侧(DynamicTableWriter 接口不变)
   ├── JdbcDynamicTableWriter   现状:表结构探测,全 NORMAL
   └── MetaTableWriter          新:元数据驱动(NORMAL/JSON/EXPAND/子表递归)

读侧(流程回显最小闭环)
   JdbcTableReader              底层行查询(按列等值,limit)
   MetaTableReader              readByProcessInstance:storageType 反序列化 + 子表组装

5. 写入语义(MetaTableWriter)

storageType写入
NORMAL直写(列名宽松匹配沿用 spec 09)
EXPAND对象字段展开为多列(address.provinceprovince 列)
JSON对象/数组序列化为 JSON 串写列
ONE2ONE子表单条递归插入(外键 = 主表主键),同事务
ONE2MANY子表多条递归插入(data 值为数组),同事务

复用现有能力:主键生成(含非自增雪花,生成器返回主键供子表外键)/ 系统字段 / 同链防重 / schema 限定探测。未消费字段(流程上下文 process_instance_id 等)直通。

中途更新(update,1.8.0):按元数据 storageType 组装 SET 列——NORMAL/JSON/EXPAND 参与更新;ONE2ONE/ONE2MANY 子表不参与中途更新(SYNC 任务推进只更新主表行状态, 子表数据变动走重新提交);未消费字段直通。无元数据回落基础 writer。

子表系统用户字段(1.8.0):子表递归插入时继承主表 apply_user_id (拦截器场景 = 流程 operator,putIfAbsent 子表单显式同名字段优先)——fillSystemFields 的用户列默认值可解析到 operator,避免 BIGINT create_user/update_user 列回落 "system" 严格模式报错(与主表行为一致)。

6. 读取语义(MetaTableReader)

java
// 按 relTableName + process_instance_id 回显一条(无分页/无条件)
Map<String, Object> readByProcessInstance(String tableName, Object processInstanceId);
storageType读取
NORMAL直读列
EXPAND反展开为对象(province/city/detail_addraddress.province/...
JSON反序列化为对象/数组
ONE2ONE按外键=主表主键查子表单条,组装为对象
ONE2MANY按外键=主表主键查子表多条,组装为数组
  • 定位键 process_instance_id(写入幂等键同款)
  • 未消费列(流程上下文/系统字段)统一小写带出(跨方言一致)
  • EXPAND 展开列不重复平铺带出(1.8.0)province/city/detail_addr 已消费为 address 对象,不再作为顶层平铺键重复出现
  • 无元数据回落原始行(列名→值)

7. 版本与发布

语言发布形态版本
Javajeeflow-persist 子模块(Maven Central)1.8.0
Gopersist/ 子包(go get 同 module)1.8.0
Pythonjeeflow.meta 模块(PyPI 随主包)1.8.0
Nodesrc/meta.ts(npm 随主包)1.8.0

jeeflow · 轻量级多语言工作流引擎