驰骋BPM-ORM设计技术报告

驰骋 BPM ORM 设计 --- 技术报告

文档版本:2026-06

章节编号:1.1

依据代码:CCFlow/Components/BP.En30(核心 ORM 组件)

说明:本文基于源码静态分析撰写,用于技术分享与方案论证,力求准确描述设计思想并客观分析优劣。


一、缘起与设计目标

1.1 起始于 2002 年

驰骋 ORM 设计起始于 2002 年 ,起因是探索可复用的企业应用框架技术。当时需要一套能够:

  • 统一描述「数据表 ↔ 实体类」的映射关系;
  • 在多种数据库(SQL Server、Oracle、MySQL 等)上复用同一套业务代码;
  • 支撑快速搭建管理类应用(增删改查、列表查询、主从表编辑)。

EntityDBAccess.cs 文件头注释仍保留着创建时间标记:

1:5:CCFlow/Components/BP.En30/En/EntityDBAccess.cs 复制代码
/*
简介:负责存取数据的类
创建时间:2002-10
最后修改时间:2002-10
*/

1.2 设计目标(与市面 ORM 的差异点)

驰骋 ORM 从一开始就不是「纯数据访问层」,而是面向企业低代码应用的元数据框架:

维度 驰骋 ORM 目标 典型 ORM(EF Core / Hibernate)目标
核心对象 表 + 字段 + 控件 + 关系 类 + 属性 + 导航属性
元数据载体 Map / Attr / Attrs(代码 + 库表双轨) 特性标注 / Fluent API / 约定
产出物 CRUD + 表单 UI + 查询面板 + 主从/多对多 CRUD + LINQ 查询
运行方式 属性值存于 Row(Hashtable),弱类型读写 强类型属性 + 变更跟踪

这一取向决定了后续 CCFlow、JFlow、低代码表单、组织结构等模块均可在同一套元数据上叠加能力,而不必重复定义字段语义。


二、演进历程:XML → Map / Attr / Attrs

2.1 第一阶段:XML 描述映射(约 2002)

早期版本用 XML 文件 表达数据表与实体类的完整关系。Map.GenerMap(string xml) 方法至今仍保留这一能力:读取 XML 中的 BaseAttrSearchAttrDtlDot2Dot 等节点,动态构建 Map 对象。

743:773:CCFlow/Components/BP.En30/En/MapExt/Map.cs 复制代码
        #region  生成属性根据xml.
        private string PKs = "";
        public void GenerMap(string xml)
        {
            DataSet ds = new DataSet("");
            ds.ReadXml(xml);
            foreach (DataTable dt in ds.Tables)
            {
                switch (dt.TableName)
                {
                    case "Base":
                        this.DealDT_Base(dt);
                        break;
                    case "Attr":
                        this.DealDT_Attr(dt);
                        break;
                    case "SearchAttr":
                        this.DealDT_SearchAttr(dt);
                        break;
                    case "Dtl":
                        this.DealDT_SearchAttr(dt);
                        break;
                    case "Dot2Dot":
                        this.DealDT_Dot2Dot(dt);
                        break;
                    default:
                        throw new Exception("XML 配置信息错误,没有约定的标记:" + dt.TableName);
                }
            }
            // 检查配置的完整性。
        }

XML 方案的优点是映射与代码解耦、便于工具生成;缺点是调试困难、版本管理成本高、缺乏编译期检查。

2.2 第二阶段:Map / Attr / Attrs 类(约 2003)

2003 年 ,架构改造为以 MapAttrAttrs 三个核心类在 C# 代码中描述映射,成为至今沿用的主路径。

职责
Map 描述一个实体(En)的完整元数据:物理表名、主键策略、字段集合、从表、多对多、查询条件、关联方法等
Attr 描述单个字段/属性:键名、物理列名、数据类型、字段逻辑类型、UI 控件、可见性、默认值、外键绑定等
Attrs Attr 的集合,提供 AddTBStringAddTBIntAddDDLEntitiesAddDDLSysEnum 等工厂方法,简化 Map 构建

实体子类通过重写 EnMap 属性返回自己的 Map 定义。以组织结构中的 Emp(用户)为例:

346:382:CCFlow/Components/BP.En30/Port/Emp.cs 复制代码
        public override Map EnMap
        {
            get
            {
                if (this._enMap != null)
                    return this._enMap;
                Map map = new Map("Port_Emp", "用户");

                #region 基本属性
                map.EnDBUrl = new DBUrl(DBUrlType.AppCenterDSN);
                map.IndexField = EmpAttr.FK_Dept;
                #endregion

                #region 字段
                map.AddTBStringPK(EmpAttr.No, null, "编号", true, false, 1, 50, 30);
                // ...
                map.AddTBString(EmpAttr.Name, null, "名称", true, false, 0, 200, 30);
                map.AddDDLEntities(EmpAttr.FK_Dept, null, "部门", new BP.Port.Depts(), false);
                // ...
                #endregion 字段

代码化 Map 带来了编译期类型安全(字段常量类如 EmpAttr)、IDE 跳转、与业务逻辑同仓版本管理等优势,XML 路径退居兼容与工具导入用途。


三、核心架构

3.1 类层次与职责

classDiagram class EnObj { +Row _row +Map _enMap +GetValByKey() +SetValByKey() } class Entity { +Insert() +Update() +Delete() +Retrieve() +CheckPhysicsTable() } class EntityNoName { PK = &#34;No&#34; } class EntityOID { PK = &#34;OID&#34; } class EntityMyPK { PK = &#34;MyPK&#34; } class Entities { +RetrieveAll() +RetrieveByAttr() } class Map { +Attrs +Dtls +AttrsOfOneVSM +AddTBString() +AddDtl() } class Attr { +Key Field +MyFieldType +UIContralType } EnObj <|-- Entity Entity <|-- EntityNoName Entity <|-- EntityOID Entity <|-- EntityMyPK Entity --> Map : EnMap Map --> Attrs Attrs --> Attr Entities --> Entity : 集合

目录结构(BP.En30

目录/文件 说明
En/ 实体基类、Map/Attr/AttrsSqlBuilderQueryObjectEntityDBAccess
DA/ 数据库访问、DBAccessDataType、缓存
Sys/ 低代码表单元数据:MapAttrMapDataMapDtlSFTableSFDBSrc
Port/ 组织结构实体(EmpDeptStation 等),均基于本 ORM 定义

3.2 数据承载:Row 弱类型模型

实体字段值不直接映射为 C# 自动属性,而是存放在 Row(继承 Hashtable 中,通过 GetValByKey / SetValByKey 读写:

13:42:CCFlow/Components/BP.En30/En/Row.cs 复制代码
    public class Row : Hashtable
    {
        // ...
        public void LoadAttrs(Attrs attrs)
        {
            this.Clear();
            foreach (Attr attr in attrs)
            {
                switch (attr.MyDataType)
                {
                    case DataType.AppInt:
                        // ...

设计意图

  • 低代码场景下字段可运行时增删,无需重新编译实体类;
  • 主表、从表、流程表单共用同一套读写 API;
  • 业务类仍可封装强类型属性(如 Emp.Name),内部转调 GetValStringByKey

3.3 持久化流水线

flowchart LR A[Entity.EnMap] --> B[SqlBuilder] B --> C[SQL + Paras] C --> D[EntityDBAccess] D --> E[DBAccess / SFDBSrc] E --> F[(数据库)] F --> G[fullDate 填充 Row]
组件 职责
SqlBuilder 根据 Map/Attrs 生成 SELECT/INSERT/UPDATE/DELETE,处理多主键、多数据库方言
SQLCache 缓存实体级 SQL 模板,减少重复拼接
EntityDBAccess 执行 SQL、异常时触发 CheckPhysicsTable 自动建表/扩列
QueryObject 链式构造 WHERE/ORDER BY,供 Entities 批量查询

3.4 主键策略

通过实体基类约定主键字段名:

基类 主键 典型场景
EntityNoName No(字符串) 部门、用户、角色、流程编号
EntityOID OID(自增整型) 运行实例、从表明细
EntityMyPK MyPK(组合字符串) DeptEmpDeptEmpStation 等关联表

FieldType 枚举进一步区分字段逻辑角色:普通、主键、外键、枚举、主键+外键、关联文本、虚拟字段等。


四、超越字段映射:BP 扩展能力

原始 ORM 仅解决「数据库列 ↔ 实体属性」映射;驰骋 BP 层在此基础上扩展为应用元数据框架

4.1 字段逻辑类型(FieldType / FieldTypeS)

141:197:CCFlow/Components/BP.En30/En/EnumLab.cs 复制代码
    public enum FieldTypeS
    {
        Normal = 0,   // 普通属性字段
        Enum = 1,     // 枚举字段
        FK = 2        // 外键字段
    }
    public enum FieldType
    {
        Normal, PK, FK, Enum, PKFK, PKEnum, RefText, NormalVirtual, MultiValues
    }
类型 含义 典型 API
属性字段 普通列,文本框/数值/日期 AddTBStringAddTBIntAddTBDate
枚举字段 绑定 Sys_Enum 或字符串枚举 AddDDLSysEnum
外键字段 绑定另一 Entities 集合 AddDDLEntities
外部数据源字段 绑定 SFTable(SQL/WS/Handler 等) UIBindKeySFTable
关联文本 外键旁的冗余显示列(如 FK_Dept + FK_DeptT 自动追加 key + "T"Attr

Attr.ToMapAttrMapAttr.HisAttr 构成代码 Map ↔ 库表 MapAttr 双向转换桥梁,使设计态(设计器保存到 Sys_MapAttr)与运行态(GenerMap() 动态生成 Map)保持一致。

4.2 控件类型映射(UIContralType)

Attr 不仅记录 MyDataType(存储类型),还记录 UIContralType(呈现控件):

  • 基础:TB(文本框)、DDL(下拉)、CheckBokRadioBtn
  • 流程/公文:HandWriting(签名)、FrmImgAth(图片附件)、GovDocFile(正文)、JobSchedule(进度图)
  • 移动端:MapPinMobilePhotoLocation

低代码表单设计器将控件配置写入 Sys_MapAttr,运行时 MapDtl.GenerMap() 遍历 MapAttrs 调用 map.AddAttr(mapAttr.HisAttr) 合成完整 Map,从而一份元数据同时驱动持久化与 UI 渲染

4.3 主表---从表映射(EnDtl)

Map.AddDtl 声明主实体下的从表集合:

516:525:CCFlow/Components/BP.En30/En/MapExt/Map.cs 复制代码
        public void AddDtl(Entities ens, string refKey, string groupName = null, DtlEditerModel model = DtlEditerModel.DtlBatch, string icon = null)
        {
            EnDtl dtl = new EnDtl();
            dtl.Ens = ens;
            dtl.RefKey = refKey;
            dtl.GroupName = this.currGroupMethodName;
            dtl.DtlEditerModel = model;
            dtl.Icon = icon;
            this.Dtls.Add(dtl);
        }
  • refKey:从表中外键列(如 FK_Node);
  • DtlEditerModel:批量编辑、查询编辑、自定义 URL 等模式;
  • 流程表单明细(MapDtl)、组织结构子面板均基于此机制。

4.4 一对多 / 多对多映射(AttrOfOneVSM)

Map.AttrsOfOneVSM 描述「一」端实体与「多」端实体通过中间表(MM 表)的关联,例如用户维护所属部门:

405:407:CCFlow/Components/BP.En30/Port/Emp.cs 复制代码
                map.AttrsOfOneVSM.AddBranches(new DeptEmps(), new BP.Port.Depts(),
                   BP.Port.DeptEmpAttr.FK_Emp,
                   BP.Port.DeptEmpAttr.FK_Dept, "部门维护", EmpAttr.Name, EmpAttr.No, "@WebUser.DeptNo");

支持树形部门、平铺面板等多种维护 UI(Dot2DotModel),直接生成部门-人员维护界面,无需手写关联 CRUD。

4.5 外部数据源(SFTable / SFDBSrc)

  • SFTable:定义下拉/列表的外部数据来源(本库 SQL、跨库、WebService、Java 处理器等);
  • SFDBSrc :多数据源连接配置,使 Map 可指定 DBSrc 指向非本地库;
  • 字段通过 UIBindKey 关联 SFTable,实现不建物理外键列也能绑定外部数据的下拉选项。

4.6 自动 DDL(CheckPhysicsTable)

实体在 Insert/Update 失败时可触发 CheckPhysicsTable():按 Map.Attrs 定义自动创建表或扩展列长。这使低代码「先画表单、后建表」成为可能,也是与「迁移脚本驱动」的 ORM 的显著差异。

4.7 查询与权限扩展

Map 还承载:

  • SearchNormals / SearchFKEnums:列表页查询条件;
  • HisRefMethods:实体关联功能(修改密码、部门角色维护等);
  • UAC:插入/删除/更新/查看权限;
  • AddHidden:数据范围过滤(如 SAAS 模式 OrgNo = @WebUser.OrgNo)。

五、生态承载:基于 ORM 构建的产品模块

驰骋 ORM 不是孤立的数据层,而是 CCFlow / JFlow / 驰骋 BPM 低代码平台 的统一元数据底座。

flowchart TB ORM[&#34;BP.En30 ORM<br/>Map / Attr / Entity / Entities&#34;] ORM --> WF[&#34;CCFlow / JFlow 工作流<br/>节点、方向、表单绑定&#34;] ORM --> Form[&#34;低代码表单<br/>MapData / MapAttr / MapDtl&#34;] ORM --> Port[&#34;组织结构<br/>Port_Emp / Port_Dept / Port_Station&#34;] ORM --> Sys[&#34;系统管理<br/>枚举、权限、数据源&#34;] WF --> Runtime[&#34;流程运行:GEEntity / GEDtl 通用实体&#34;] Form --> Runtime Port --> Worker[&#34;选人引擎:部门+角色 SQL&#34;]
模块 与 ORM 的关系
驰骋 BPM / CCFlow 流程模板、节点、表单均用 Entity/Entities 定义;运行期表单数据通过 GEEntity(通用实体)+ 动态 GenerMap() 读写
JFlow Java 版移植同一套 Map/Attr 语义,保持跨语言元数据一致
低代码 设计器操作 Sys_MapData/Sys_MapAttr;运行时合成 Map;主从表、外键、枚举、外部数据源均落在 Attr 扩展属性上
组织结构 Port_* 五表实体均在 BP.PortEnMap 声明;DeptEmpDeptEmpStationEntityMyPK;人员界面用 AttrsOfOneVSM 维护多部门
权限 / 报表 / 接口 统一 GetValByKey 读写;QueryObject 构造列表;ToJsonObject() 输出 API

结论:更换 ORM 意味着重写元数据模型、表单设计器、流程引擎数据层、组织结构集成接口------成本极高,因此该 ORM 是平台级基础设施而非可插拔组件。


六、与市面 ORM 的对比评估

6.1 对比总表

维度 驰骋 ORM(BP.En30) 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 体系) 中高

6.2 驰骋 ORM 的优势

  1. 元数据一体 :同一 Attr 描述列类型、控件、外键、枚举、默认值,设计器与运行引擎零阻抗。
  2. 企业功能内建:主从表、多对多维护、列表查询、权限位、关联方法,减少重复劳动。
  3. 低代码原生 :运行期可 GenerMap(),字段可来自数据库配置,适合用户自定义表单。
  4. 久经生产验证:2002 年至今,与 CCFlow 流程场景深度耦合(附件、签名、公文、轨迹等控件类型)。
  5. 多数据库与国产库EntityDBAccess 内可见 Oracle、MySQL、PostgreSQL、达梦、人大金仓等分支。

6.3 驰骋 ORM 的局限

  1. 非标准 ORM:无法直接用于普通 .NET 项目的「引包即用」,与 EF Core 生态(LINQ、迁移、工具链)不兼容。
  2. 弱类型 Row:大型团队纯代码开发时,缺少编译期字段检查,重构依赖全局搜索。
  3. 无现代查询抽象 :没有 LINQ / IQueryable,复杂查询依赖 SqlBuilder 字符串,可读性与组合性弱于 EF。
  4. 无变更跟踪 :更新需显式调用 Update() 并指定字段,易遗漏或误更新。
  5. XML 遗产GenerMap(xml) 与代码 EnMap 双路径并存,增加维护心智负担。
  6. 测试与 MockEntityDBAccess 静态耦合紧密,单元测试需依赖数据库或大量封装。

6.4 适用场景判断

场景 建议
驰骋 BPM / CCFlow / JFlow 二次开发 必须使用本 ORM,无替代
低代码表单 + 流程 + 组织结构一体部署 最适合
全新 .NET 业务系统、与 BPM 无关 不推荐,应选 EF Core + 独立 DTO
仅需高性能只读查询 可在 Entities 层旁路 DBAccess.RunSQL,但失去元数据收益
与外部 ORM 共存 仅建议边界清晰的数据同步,避免同一表双映射

七、典型开发模式示例

7.1 声明式实体(代码优先)

csharp 复制代码
// 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();
}

7.2 运行时使用

csharp 复制代码
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);

7.3 低代码动态表单(元数据优先)

  1. 设计器保存字段 → Sys_MapAttr
  2. MapDtl.GenerMap() / MapData.GenerMap() 合成 Map
  3. GEDtl / GEEntity 作为通用实体承载数据;
  4. 前端根据 MapAttr JSON 渲染控件。

八、总结

驰骋 ORM 是一段从 2002 年 XML 映射 演进到 2003 年 Map/Attr/Attrs 代码化元数据 、并在二十余年中持续扩展为低代码应用框架底座的技术路线。

它的本质不是「对象---关系映射库」,而是:

用统一的 Map 元数据,同时描述数据库结构、实体行为、UI 控件、主从与多对多关系、外部数据源与查询条件,并驱动 CCFlow、JFlow、组织结构与低代码表单的全生命周期。

与 Entity Framework、Hibernate 等市面 ORM 相比,驰骋 ORM 在标准性、强类型、现代查询 上不占优,但在低代码、流程、表单、组织一体化场景具有不可替代的语义内聚优势。理解这一边界,是正确使用和扩展驰骋 BPM 平台的前提。


附录:核心类型索引

类型 路径 说明
Map En/MapExt/Map.cs 实体元数据根对象
Attr / Attrs En/MapExt/Attr.cs 字段元数据与集合
Entity / Entities En/Entity.csEn/Entities.cs 实体与集合基类
Row En/Row.cs 字段值容器
SqlBuilder En/SqlBuilder.cs SQL 生成
EntityDBAccess En/EntityDBAccess.cs 持久化执行
QueryObject En/QueryObject.cs 查询构造器
EnDtl / AttrOfOneVSM En/EnDtl.csEn/MapExt/AttrOfOneVSM.cs 从表与多对多
MapAttr Sys/MapAttr.cs 低代码字段元数据(库表)
MapData / MapDtl Sys/MapData.csSys/MapDtl.cs 表单/从表定义
SFTable / SFDBSrc Sys/SFTable.csSys/SFDBSrc.cs 外部数据源
相关推荐
码哥字节2 天前
码哥用扣子搭了一套自动跟进工作流,每天省2小时这不是夸张
工作流引擎·coze
驰骋工作流3 天前
驰骋JFlow,BPM,CCFlow 异表单分合流需求列表
工作流引擎·bpm·jflow·开源驰骋低代码·ccflow·ccfast
驰骋工作流4 天前
驰骋 BPM(CCFlow/JFlow)四大运行模式与 Flowable/Camunda 技术对比
工作流引擎·工作流·bpm
SuniaWang15 天前
《AgentX 专栏》08-工作流引擎:AgentWorkflow怎么把工具记忆流程串成一条流水线
java·ai·架构·langchain·工作流引擎·langgraph·agent架构
驰骋工作流23 天前
CCFast 驰骋低代码BPM-积木菜单设计思想
低代码·工作流引擎·工程引擎·菜单体系
迪迦AI智能体24 天前
一个内容生产 AI 工作流的设计思路:任务状态、知识库与人工审核
工作流引擎
Flynt2 个月前
用AI自动生成科研工作流:原理、架构与局限性
agent·工作流引擎
流之云低代码平台3 个月前
突破传统,PHP工作流引领软件开发新潮流
工作流引擎·系统可靠性·php工作流技术·软件开发效能·业务流程自动化·系统灵活性
决斗小饼干3 个月前
拒绝扯皮!3步搞定工作流,我被JNPF硬控了15分钟
低代码·工作流引擎