本文基于源码分析梳理一套元数据驱动 ORM 的设计:从早期 XML 映射到代码化 Map 体系,再到主从表、外部数据源与自动建表等扩展机制,并给出与主流 ORM 的对比及适用场景建议。
该平台 ORM 设计起始于 2002 年,起因是探索可复用的企业应用框架技术。当时需要一套能够:
EntityDBAccess.cs 文件头注释仍保留着创建时间标记:
该平台 ORM 从一开始就不是「纯数据访问层」,而是面向企业低代码应用的元数据框架:
维度 | 该平台 ORM 目标 | 典型 ORM(EF Core / Hibernate)目标 |
|---|---|---|
核心对象 | 表 + 字段 + 控件 + 关系 | 类 + 属性 + 导航属性 |
元数据载体 | Map / Attr / Attrs(代码 + 库表双轨) | 特性标注 / Fluent API / 约定 |
产出物 | CRUD + 表单 UI + 查询面板 + 主从/多对多 | CRUD + LINQ 查询 |
运行方式 | 属性值存于 Row(Hashtable),弱类型读写 | 强类型属性 + 变更跟踪 |
这一取向决定了后续 该引擎、该引擎、低代码表单、组织结构等模块均可在同一套元数据上叠加能力,而不必重复定义字段语义。
早期版本用 XML 文件表达数据表与实体类的完整关系。Map.GenerMap(string xml) 方法至今仍保留这一能力:读取 XML 中的 Base、Attr、SearchAttr、Dtl、Dot2Dot 等节点,动态构建 Map 对象。
XML 方案的优点是映射与代码解耦、便于工具生成;缺点是调试困难、版本管理成本高、缺乏编译期检查。
2003 年,架构改造为以 Map、Attr、Attrs 三个核心类在 C# 代码中描述映射,成为至今沿用的主路径。
类 | 职责 |
|---|---|
Map | 描述一个实体(En)的完整元数据:物理表名、主键策略、字段集合、从表、多对多、查询条件、关联方法等 |
Attr | 描述单个字段/属性:键名、物理列名、数据类型、字段逻辑类型、UI 控件、可见性、默认值、外键绑定等 |
Attrs | Attr 的集合,提供 AddTBString、AddTBInt、AddDDLEntities、AddDDLSysEnum 等工厂方法,简化 Map 构建 |
实体子类通过重写 EnMap 属性返回自己的 Map 定义。以组织结构中的 Emp(用户)为例:
代码化 Map 带来了编译期类型安全(字段常量类如 EmpAttr)、IDE 跳转、与业务逻辑同仓版本管理等优势,XML 路径退居兼容与工具导入用途。
目录结构(引擎内核命名空间):
目录/文件 | 说明 |
|---|---|
En/ | 实体基类、Map/Attr/Attrs、SqlBuilder、QueryObject、EntityDBAccess |
DA/ | 数据库访问、DBAccess、DataType、缓存 |
Sys/ | 低代码表单元数据:MapAttr、MapData、MapDtl、SFTable、SFDBSrc |
Port/ | 组织结构实体(Emp、Dept、Station 等),均基于本 ORM 定义 |
实体字段值不直接映射为 C# 自动属性,而是存放在 Row(继承 Hashtable) 中,通过 GetValByKey / SetValByKey 读写:
设计意图:
Emp.Name),内部转调 GetValStringByKey。组件 | 职责 |
|---|---|
SqlBuilder | 根据 Map/Attrs 生成 SELECT/INSERT/UPDATE/DELETE,处理多主键、多数据库方言 |
SQLCache | 缓存实体级 SQL 模板,减少重复拼接 |
EntityDBAccess | 执行 SQL、异常时触发 CheckPhysicsTable 自动建表/扩列 |
QueryObject | 链式构造 WHERE/ORDER BY,供 Entities 批量查询 |
通过实体基类约定主键字段名:
基类 | 主键 | 典型场景 |
|---|---|---|
EntityNoName | No(字符串) | 部门、用户、角色、流程编号 |
EntityOID | OID(自增整型) | 运行实例、从表明细 |
EntityMyPK | MyPK(组合字符串) | DeptEmp、DeptEmpStation 等关联表 |
FieldType 枚举进一步区分字段逻辑角色:普通、主键、外键、枚举、主键+外键、关联文本、虚拟字段等。
原始 ORM 仅解决「数据库列 ↔ 实体属性」映射;该平台 BP 层在此基础上扩展为应用元数据框架。
类型 | 含义 | 典型 API |
|---|---|---|
属性字段 | 普通列,文本框/数值/日期 | AddTBString、AddTBInt、AddTBDate |
枚举字段 | 绑定 Sys_Enum 或字符串枚举 | AddDDLSysEnum |
外键字段 | 绑定另一 Entities 集合 | AddDDLEntities |
外部数据源字段 | 绑定 SFTable(SQL/WS/Handler 等) | UIBindKey → SFTable |
关联文本 | 外键旁的冗余显示列(如 FK_Dept + FK_DeptT) | 自动追加 key + "T" 的 Attr |
Attr.ToMapAttr 与 MapAttr.HisAttr 构成代码 Map ↔ 库表 MapAttr 双向转换桥梁,使设计态(设计器保存到 Sys_MapAttr)与运行态(GenerMap() 动态生成 Map)保持一致。
Attr 不仅记录 MyDataType(存储类型),还记录 UIContralType(呈现控件):
TB(文本框)、DDL(下拉)、CheckBok、RadioBtnHandWriting(签名)、FrmImgAth(图片附件)、GovDocFile(正文)、JobSchedule(进度图)MapPin、MobilePhoto、Location低代码表单设计器将控件配置写入 Sys_MapAttr,运行时 MapDtl.GenerMap() 遍历 MapAttrs 调用 map.AddAttr(mapAttr.HisAttr) 合成完整 Map,从而一份元数据同时驱动持久化与 UI 渲染。
Map.AddDtl 声明主实体下的从表集合:
refKey:从表中外键列(如 FK_Node);DtlEditerModel:批量编辑、查询编辑、自定义 URL 等模式;MapDtl)、组织结构子面板均基于此机制。Map.AttrsOfOneVSM 描述「一」端实体与「多」端实体通过中间表(MM 表)的关联,例如用户维护所属部门:
支持树形部门、平铺面板等多种维护 UI(Dot2DotModel),直接生成部门-人员维护界面,无需手写关联 CRUD。
SFTable:定义下拉/列表的外部数据来源(本库 SQL、跨库、WebService、Java 处理器等);SFDBSrc:多数据源连接配置,使 Map 可指定 DBSrc 指向非本地库;UIBindKey 关联 SFTable,实现不建物理外键列也能绑定外部数据的下拉选项。实体在 Insert/Update 失败时可触发 CheckPhysicsTable():按 Map.Attrs 定义自动创建表或扩展列长。这使低代码「先画表单、后建表」成为可能,也是与「迁移脚本驱动」的 ORM 的显著差异。
Map 还承载:
SearchNormals / SearchFKEnums:列表页查询条件;HisRefMethods:实体关联功能(修改密码、部门角色维护等);UAC:插入/删除/更新/查看权限;AddHidden:数据范围过滤(如 SAAS 模式 OrgNo = @WebUser.OrgNo)。该平台 ORM 不是孤立的数据层,而是 该引擎 / 该引擎 / 该 BPM 平台 低代码平台 的统一元数据底座。
模块 | 与 ORM 的关系 |
|---|---|
该 BPM 平台 / 该引擎 | 流程模板、节点、表单均用 Entity/Entities 定义;运行期表单数据通过 GEEntity(通用实体)+ 动态 GenerMap() 读写 |
该引擎 | Java 版移植同一套 Map/Attr 语义,保持跨语言元数据一致 |
低代码 | 设计器操作 Sys_MapData/Sys_MapAttr;运行时合成 Map;主从表、外键、枚举、外部数据源均落在 Attr 扩展属性上 |
组织结构 | Port_* 五表实体均在 引擎内核命名空间 用 EnMap 声明;DeptEmp、DeptEmpStation 用 EntityMyPK;人员界面用 AttrsOfOneVSM 维护多部门 |
权限 / 报表 / 接口 | 统一 GetValByKey 读写;QueryObject 构造列表;ToJsonObject() 输出 API |
结论:更换 ORM 意味着重写元数据模型、表单设计器、流程引擎数据层、组织结构集成接口——成本极高,因此该 ORM 是平台级基础设施而非可插拔组件。
维度 | 该平台 ORM(引擎内核命名空间) | Entity Framework Core | Hibernate / JPA | Dapper |
|---|---|---|---|---|
定位 | 元数据 + ORM + UI 描述 | 标准 .NET ORM | Java 标准 ORM | 微 ORM / SQL 映射 |
映射定义 | Map/Attr 代码 + Sys_MapAttr 库表 | 特性 / Fluent API | 注解 / XML | 手写 SQL |
查询方式 | QueryObject + SqlBuilder | LINQ | HQL / Criteria / JPQL | 原始 SQL |
变更跟踪 | 无(显式 Update) | 有 | 有(Session) | 无 |
UI 元数据 | 内置(控件、布局、从表) | 无 | 无 | 无 |
主从 / 多对多 | EnDtl / AttrOfOneVSM 一等公民 | 导航属性配置 | 关联映射 | 自行实现 |
自动建表 | CheckPhysicsTable | Migrations | hbm2ddl | 无 |
多数据库 | SqlBuilder 方言分支 | 提供商插件 | 方言 | 取决于 SQL |
低代码友好 | 极高 | 低 | 低 | 低 |
强类型开发体验 | 中(Row + 部分封装属性) | 高 | 高 | 高 |
学习曲线(纯 CRUD) | 中(需理解 Map 体系) | 中 | 中高 | 低 |
Attr 描述列类型、控件、外键、枚举、默认值,设计器与运行引擎零阻抗。GenerMap(),字段可来自数据库配置,适合用户自定义表单。EntityDBAccess 内可见 Oracle、MySQL、PostgreSQL、达梦、人大金仓等分支。SqlBuilder 字符串,可读性与组合性弱于 EF。Update() 并指定字段,易遗漏或误更新。GenerMap(xml) 与代码 EnMap 双路径并存,增加维护心智负担。Entity 与 DBAccess 静态耦合紧密,单元测试需依赖数据库或大量封装。场景 | 建议 |
|---|---|
该 BPM 平台 / 该引擎 / 该引擎 二次开发 | 必须使用本 ORM,无替代 |
低代码表单 + 流程 + 组织结构一体部署 | 最适合 |
全新 .NET 业务系统、与 BPM 无关 | 不推荐,应选 EF Core + 独立 DTO |
仅需高性能只读查询 | 可在 Entities 层旁路 DBAccess.RunSQL,但失去元数据收益 |
与外部 ORM 共存 | 仅建议边界清晰的数据同步,避免同一表双映射 |
// 1. 字段常量类
public class XxxAttr { public const string Title = "Title"; }
// 2. 实体类
public class Xxx : EntityNoName
{
public override Map EnMap
{
get
{
if (_enMap != null) return _enMap;
Map map = new Map("My_Xxx", "示例");
map.AddTBStringPK(XxxAttr.No, null, "编号", true, false, 1, 50, 20);
map.AddTBString(XxxAttr.Title, null, "标题", true, false, 0, 200, 30);
map.AddDDLSysEnum("Status", 0, "状态", true, false, "XxxStatus");
_enMap = map;
return _enMap;
}
}
}
// 3. 集合类
public class Xxxs : EntitiesNoName
{
public override Entity GetNewEntity => new Xxx();
}Xxx en = new Xxx();
en.No = "001";
en.SetValByKey(XxxAttr.Title, "测试");
en.Insert();
Xxxs ens = new Xxxs();
ens.RetrieveByAttr("Status", 1);
Xxx en2 = new Xxx("001");
en2.RetrieveFromDBSources();
string title = en2.GetValStringByKey(XxxAttr.Title);Sys_MapAttr;MapDtl.GenerMap() / MapData.GenerMap() 合成 Map;GEDtl / GEEntity 作为通用实体承载数据;MapAttr JSON 渲染控件。该平台 ORM 是一段从 2002 年 XML 映射演进到 2003 年 Map/Attr/Attrs 代码化元数据、并在二十余年中持续扩展为低代码应用框架底座的技术路线。
它的本质不是「对象—关系映射库」,而是:
用统一的
Map元数据,同时描述数据库结构、实体行为、UI 控件、主从与多对多关系、外部数据源与查询条件,并驱动 该引擎、该引擎、组织结构与低代码表单的全生命周期。
与 Entity Framework、Hibernate 等市面 ORM 相比,该平台 ORM 在标准性、强类型、现代查询上不占优,但在低代码、流程、表单、组织一体化场景具有不可替代的语义内聚优势。理解这一边界,是正确使用和扩展该 BPM 平台 平台的前提。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。