当前位置: 首页 > news >正文

用户自定义字段(Custom Fields)设计方案,兼顾多语言、分组、校验、权限、查询性能、审计与多租户

1. 核心理念

  • 字段=元数据:把“字段”本身当数据管理(而不是改表结构)。
  • 值=数据:业务记录与字段定义分离存储。
  • 渲染=规则:前端按字段元数据动态渲染表单与详情;后端按校验规则校验。

2. 适用场景与存储策略

三种常见模型,可混合使用:

  1. EAV(Entity–Attribute–Value):适合“字段很多但稀疏”的大规模扩展;查询复杂度高。
  2. JSON 列(推荐 for PG):主表保留 extra_fields jsonb,查询用 GIN 索引与生成列;实现简单,性能可控。
  3. 派生物化列:对高频查询的关键自定义字段,使用生成列/冗余列同步表提升检索性能。

在 PostgreSQL/云原生环境中,建议:主表 + jsonb + GIN 索引,对热点字段再加生成列物化视图

3. 元数据建模(字段定义)

最小可用的 4 张表(支持多租户、分组、排序、i18n、权限与校验):

-- 自定义表单/实体(例如:文物、资产、客户…)
CREATE TABLE cf_entity (id            BIGSERIAL PRIMARY KEY,tenant_id     BIGINT NOT NULL,code          VARCHAR(64) NOT NULL UNIQUE,     -- 如 "artifact"name_i18n_key VARCHAR(128) NOT NULL,           -- i18n keystatus        SMALLINT DEFAULT 1,              -- 1启用/0禁用created_at    TIMESTAMP NOT NULL DEFAULT NOW()
);-- 字段分组(用于页面分区与折叠)
CREATE TABLE cf_field_group (id            BIGSERIAL PRIMARY KEY,tenant_id     BIGINT NOT NULL,entity_code   VARCHAR(64) NOT NULL,code          VARCHAR(64) NOT NULL,name_i18n_key VARCHAR(128) NOT NULL,sort_order    INT DEFAULT 0
);-- 字段定义(元数据核心)
CREATE TABLE cf_field_def (id               BIGSERIAL PRIMARY KEY,tenant_id        BIGINT NOT NULL,entity_code      VARCHAR(64) NOT NULL,group_code       VARCHAR(64),                   -- 归属分组field_key        VARCHAR(64) NOT NULL,          -- 唯一键,如 "material"label_i18n_key   VARCHAR(128) NOT NULL,         -- 标签 i18ntype             VARCHAR(32) NOT NULL,          -- text/textarea/number/date/datetime/select/multi_select/switch/image/file/ref/...required         BOOLEAN DEFAULT FALSE,visible          BOOLEAN DEFAULT TRUE,editable         BOOLEAN DEFAULT TRUE,unique_scope     VARCHAR(32),                   -- unique_in_entity / unique_in_tenant / nullplaceholder_i18n_key VARCHAR(128),help_i18n_key    VARCHAR(128),default_value    JSONB,                         -- 默认值(随类型)options          JSONB,                         -- 选项(下拉/多选)/远程数据源配置/联动规则等validate_rules   JSONB,                         -- 校验规则:正则、最小最大值、长度、必填条件表达式permission_expr  JSONB,                         -- 权限规则:roles、scopes、dept、dataScopesort_order       INT DEFAULT 0,version          INT DEFAULT 1,                 -- 版本(用于灰度与历史追溯)status           SMALLINT DEFAULT 1,updated_at       TIMESTAMP NOT NULL DEFAULT NOW()
);-- 选项字典(可独立维护,或放到 options 中)
CREATE TABLE cf_option (id            BIGSERIAL PRIMARY KEY,tenant_id     BIGINT NOT NULL,field_key     VARCHAR(64) NOT NULL,value         VARCHAR(128) NOT NULL,label_i18n_key VARCHAR(128) NOT NULL,sort_order    INT DEFAULT 0,enabled       BOOLEAN DEFAULT TRUE
);

4. 业务数据建模

4.1 主业务表(建议 jsonb 承载)

-- 示例:artifact 文物主表(只展示关键列)
CREATE TABLE artifact (id            BIGSERIAL PRIMARY KEY,tenant_id     BIGINT NOT NULL,name          VARCHAR(255) NOT NULL,extra_fields  JSONB DEFAULT '{}'::jsonb,        -- 自定义字段值created_at    TIMESTAMP NOT NULL DEFAULT NOW()
);-- GIN 索引支持 key/contain 查询
CREATE INDEX idx_artifact_extra_fields ON artifact USING GIN (extra_fields jsonb_path_ops);-- 对高频字段生成列(便于排序/where/join)
ALTER TABLE artifactADD COLUMN material GENERATED ALWAYS AS ((extra_fields->>'material')) STORED;CREATE INDEX idx_artifact_material ON artifact(material);

4.2 EAV(如需)

CREATE TABLE cf_value (id           BIGSERIAL PRIMARY KEY,tenant_id    BIGINT NOT NULL,entity_code  VARCHAR(64) NOT NULL,record_id    BIGINT NOT NULL,          -- 关联业务记录idfield_key    VARCHAR(64) NOT NULL,value_text   TEXT,value_num    NUMERIC(20,6),value_time   TIMESTAMP,value_json   JSONB,UNIQUE(tenant_id, entity_code, record_id, field_key)
);

5. 字段生命周期与版本

  • 草稿→发布:字段定义支持版本号与状态;新版本发布对新建记录生效,老记录继续可读。
  • 禁用/删除:仅标记禁用;保留历史值。
  • 迁移器:当字段类型变化(如 text→select),提供后台数据迁移工具与回滚脚本。

6. 权限与可见性

  • permission_expr 用于表达:roles: ["curator","admin"], scopes:["artifact:edit"],以及条件可见/可编辑(基于租户、部门、记录状态)。
  • 后端在读定义保存值时都要二次校验,前端仅做 UX 限制。

7. 校验与联动

  • validate_rules 结构示例:
{"requiredIf": "record.state == 'ON_SHOW'","regex": "^[A-Za-z0-9-]{1,32}$","min": 0,"max": 1000,"maxLength": 64,"custom": "script: value.startsWith('NHB-')"   // 可选:受控脚本/DSL
}
  • options 可配置远程数据源、联动逻辑:
{"datasource": { "type": "dict", "code": "MATERIAL_TYPE" },"cascade": { "parent": "category", "api": "/api/materials?cat=${value}" },"ui": { "widget": "select", "multiple": false, "clearable": true }
}

8. 查询与性能

  • 常用查询走生成列或物化视图;

  • 复杂筛选jsonb_path_query / @>

  • 索引策略

    • GIN on (extra_fields)
    • 针对关键路径的表达式索引CREATE INDEX ON artifact ((extra_fields->>'material'));
  • 归档:历史大表分区;冷数据移仓。

9. 审计与历史

  • cf_field_def_audit:记录字段定义变更(谁、何时、前后对比 diff)。
  • cf_value_audit:记录业务字段值变更(包含旧值/新值、校验结果、IP)。
  • 便于合规(如政府项目)与问题回溯。

10. API 设计(REST/GraphQL)

  • GET /cf/entities/{entityCode}/fields?include=groups,options
  • POST /cf/entities/{entityCode}/fields(增/改字段定义,需审批或发布)
  • GET /{entityCode}/{id}(返回业务数据 + 已过滤的字段定义)
  • PUT /{entityCode}/{id}(提交 extra_fields,后端按定义校验 + 权限)
  • POST /cf/search/{entityCode}(复杂筛选:结构化条件 + JSON 路径)

后端校验伪码:

// pseudo
Map<String, Object> values = request.getExtraFields();
List<FieldDef> defs = fieldService.listFor(entityCode, tenantId, roleCtx);
for (FieldDef def : defs) {if (!def.visible || !def.editableBy(roleCtx)) continue;Object v = values.get(def.fieldKey);validateRequired(def, v, recordCtx);validateType(def.type, v);validateRules(def.validateRules, v, recordCtx); // regex/min/max/customvalidateUnique(def.uniqueScope, def.fieldKey, v, recordId, tenantId);
}
save(values);

11. 前端渲染(React 示例思路)

  • 拉取 entityCode字段定义 + 分组
  • group.sort_order 分区,按 field.sort_order 排序;
  • 根据 type 映射组件(Input/Select/Checkbox/DatePicker/Upload/ImageCropper/RefPicker…);
  • 根据 permission_expr 控制 disabled/hidden
  • 根据 validate_rules 生成 Form 规则;
  • 多语言从 *_i18n_key 取词条。

字段定义→渲染映射(示例)

type WidgetMap = {text: Input;number: InputNumber;date: DatePicker;datetime: DatePicker; // showTimeselect: Select;multi_select: Select; // mode="multiple"switch: Switch;image: Upload;file: Upload;ref: RemoteSelect;    // 可搜索引用其它实体
};

12. 多租户与隔离

  • 所有表加 tenant_id
  • 字段定义可租户级平台级(全租户可用),平台级字段在租户端可“继承 + 局部覆盖 UI/校验”;
  • 数据访问层统一注入 tenant_id 过滤器(例如 MyBatis 拦截器)。

13. 报表与导出

  • 导出时根据最新字段定义动态列头(i18n 标签)与类型格式化
  • 对“超宽表”导出,提供选择字段分页导出
  • 为常用字段建立物化视图用于 BI 查询。

14. 变更治理与灰度

  • 草稿/发布两套集合,发布后标注 active_version
  • 前端带版本号请求;
  • 支持字段级灰度(按租户/部门/角色启用新字段)。

15. 典型坑与规避

  • 查询慢:未加 GIN/表达式索引;把所有筛选都丢给 jsonb。
  • 无限制脚本校验:使用受限 DSL/白名单,避免注入与性能风险。
  • 字段滥用:缺少审批流与命名规范([模块]-[业务]-[含义])。
  • 强删字段:历史数据丢失;应软删 + 数据迁移器。
  • 权限只做前端:必须后端再校验。

速用清单

  • jsonb + GIN 存值;高频筛选做生成列/表达式索引
  • 4 张元数据表:cf_entity / cf_field_group / cf_field_def / cf_option
  • 字段定义含 i18n、分组、排序、校验、权限、默认值、选项、联动、版本
  • API:获取定义→渲染;提交值→后端统一校验→持久化。
  • 审计与灰度:定义与值都做版本/审计,字段变更有迁移器
http://www.dtcms.com/a/357702.html

相关文章:

  • LeetCode - 128. 最长连续序列
  • LeetCode第二题知识点3 ----引用类型
  • lxml库如何使用
  • DSP280049 CLA可访问资源
  • 【开题答辩全过程】以 非遗信息管理系统为例,包含答辩的问题和答案
  • 2025年企业管理与经济、文化发展国际会议(MECD 2025)
  • 拎包入住搭建 Browser Use Agent:基于PPIO Model API +Agent 沙箱的一体化构建
  • React-Native项目回忆
  • QML Chart组件之坐标轴共有属性
  • 基于Springboot + vue3实现的教育资源共享平台
  • Java流程控制03——顺序结构(本文为个人学习笔记,内容整理自哔哩哔哩UP主【遇见狂神说】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
  • PCIe 6.0 TLP路由机制:解密高效数据传输的核心架构
  • 贪心算法面试常见问题分类解析
  • 了解 JavaScript 虚拟机(VM)引擎
  • 【项目思维】编程思维学习路线(推荐)
  • Simulink过程数据存储为mat
  • PHP的header()函数分析
  • Web开发工具一套式部署Maven/Nvm/Mysql/Redis
  • 迅睿CMS标签工具箱v1.1版本已更新
  • C++ STL之封装红黑树实现map/set
  • linux系统学习(15.启动管理)
  • Anaconda安装与conda使用详细版
  • 杨校老师竞赛课堂之C++语言GESP一级笔记
  • JUC并发编程09 - 内存(01) - JMM/cache
  • HITTER——让双足人形打乒乓球(且可根据球的走向移动脚步):高层模型规划器做轨迹预测和击球规划,低层RL控制器完成击球
  • windows下安装redis
  • fcitx5-rime自动部署的实现方法
  • ​Windows8.1-KB2934018-x64.msu 怎么安装?Windows 8.1 64位补丁安装教程​(附安装包下载)
  • Linux按键驱动开发
  • 基于 Vue + Interact.js 实现可拖拽缩放柜子设计器