【开源】跨语言·跨平台·跨数据库(3) ------为用宝框架增加ORM,让AI执行
2026-07-13
作者:周方勇 / 咏方舟-长江支流(金质打印通、用宝框架开源作者)
用宝框架 · 拥抱第一 · 一次书写 · 三端复用
用宝框架是轻量级企业级分层架构基架,也是开放的、可扩展的架构体系 。.NET Standard 2.0,零依赖,支持 MySQL / SQL Server / Oracle / SQLite并可扩展。SQL就是最好的跨平台语言 ,可跨语言无缝迁移至鸿蒙 ArkTS 及 Java 技术栈,接口名、类名、方法签名三端完全一致。
用宝架构开发的所有应用,可直接移植到 Java/ArkTS,无需重新设计架构、无需重新分层、无需重新抽象业务逻辑,只需按目标语言语法做形式上的转换。
本文侧重:为用宝框架增加轻量级 ORM,在不改变核心基架的前提下,获得实体映射 + 自动 SQL 生成能力,增删改查完全不用写代码。本篇将20年前无泛型、无依赖注入、无EF时的轻量级设计重新整理,形成完整的设计文档与约束规范,让AI按照规范自动执行生成代码。当然,为了代码生成少些bug,我提供了之前源码,特别是CommandTextBuilder。人工不仅是设计师,更是有与AI沟通的能力,以及程序员协助调试Bug的能力,AI作为执行者将更大幅提升效率。

用宝架构 ORM 扩展设计总结(跨语言版)
前言:用宝框架的轻量与开放
用宝框架首先是轻量级 的------UserBaoTech.Foundation 核心库仅依赖 System.Text.Json,零 ORM 绑定,零重量级抽象,保持最小依赖和最大可移植性。
但用宝框架也是开放的------核心不预设任何具体实现,所有组件通过接口可替换、可扩展。这种设计既保障了基座的稳定性,也为上层功能的生长留出了空间。
本篇的目的,就是为用宝框架增加一个 ORM 扩展模块:让开发者在不改变核心基架的前提下,获得"实体映射 + 自动 SQL 生成 + 事件钩子"的便利能力。
本篇的目的,就是为用宝框架增加一个 ORM 扩展模块:让开发者在不改变核心基架的前提下,获得"实体映射 + 自动 SQL 生成 + 事件钩子"的便利能力。
💡 AI 时代的编程思想:人是设计师,AI 是执行者
以下设计不仅是给开发者阅读的编码依据,也是给 AI 执行的指令集。设计越详细、规范越清晰、约束越明确,AI 生成的代码质量就越高,越不需要人工修改。
你用宝框架定义好了"怎么写"(接口、基类、命名规范、跨语言约束),AI 只需要根据表结构填空生成"写什么"(实体、仓储、服务、控制器)。
这就是 AI 时代程序员的核心竞争力------从"写代码的人"进化为"设计架构、定义规范、指挥 AI 执行的人"。
同时,这个扩展模块必须继承用宝框架的跨语言设计约束:
- 接口定义中不使用
IList<T>、List<T>、IDictionary<TKey, TValue>等特定语言集合类型 - 统一使用 数组
T[]表示集合,因为数组在 C#、Java、ArkTS 中都是原生语法,不需要额外引入命名空间或类库 - 这一原则贯穿整个 ORM 模块的设计,确保用宝框架的业务代码可以直接"拷过去用",而不是靠"翻译器"转换
这就是用宝框架的"轻量·开放·跨语言"三位一体设计。
这套轻量级 ORM 的设计,早在 2007年就已在 CSDN 上公开分享(当时用的是 2004 年写的源码),至今约 20 年。相关文章:
只是今天,在用宝框架上,我根据框架轻量化特点,应用跨平台并通用于java、ArcTS通用语言,重新设计。你如果将本篇投喂给AI,AI也可以帮你完成代码书写,但如果再把用宝技术轻量框架的设计一起发给AI,那生成的ORM代码就更适合用宝框架。
【开源】跨语言·跨平台·跨数据库(1) ------ 用宝技术轻量框架 AI 开发指南
【开源】跨语言·跨平台·跨数据库(2) ------ 用宝轻量框架设计必读
一、用宝架构现有核心(已有,无需改动)
-
命名空间 :
UserBaoTech.Foundation -
核心抽象:
IEntity<TKey>:实体基接口(Id、CreatedAt、UpdatedAt、IsDeleted)IRepository<T>:泛型仓储接口(CRUD + 执行 SQL)RepositoryBase<T>:仓储基类,提供默认 CRUD 实现,子类需实现表名、映射、插入/更新值IDataAccessExecutor:数据访问执行器,封装连接、事务、SQL 执行及方言适配(参数前缀、分页、自增回读)IUnitOfWork:工作单元,管理事务边界ServiceBase<TParam,TResult>/KeyServiceBase<TResult>:业务服务基类,模板方法模式MessageResult<T>:统一返回格式QueryParametersBase:查询参数基类- 基础设施接口:
ILogger、ICacheProvider、IConfigProvider(可插拔)
-
设计原则 :轻量、零依赖(仅
System.Text.Json)、跨语言可迁移、接口优先、基类提供默认实现。
二、ORM 扩展目标
在 不改变现有核心基架 的前提下,增加一个可选的 ORM 模块,提供:
- 实体映射:通过特性标记或手写元数据,将实体类与数据库表、字段、主键关联。
- 自动 SQL 生成 :根据实体元数据自动生成
INSERT/UPDATE/DELETE/SELECT语句,无需手动写 SQL。 - 实体存取接口 :提供类似旧
IEntityAccess的增删改查操作,并通过虚方法钩子(而非事件委托)提供扩展点,方便业务定制。 - 与现有框架无缝集成 :复用
IDataAccessExecutor执行 SQL,复用IUnitOfWork管理事务。
三、新增命名空间与核心接口
命名空间:UserBaoTech.Foundation.ORM
1. 可映射实体接口 IMapEntity<TKey>
继承自 IEntity<TKey>,增加表结构元数据获取方法:
csharp
public interface IMapEntity<TKey> : IEntity<TKey>
{
// 表名
string TableName { get; }
// 主键列表(支持复合主键)
string[] PrimaryKeys { get; }
// 字段列表
string[] GetFields();
// 字段值列表(与 GetFields() 顺序一致)
object[] GetFieldValues();
// 主键值列表
object[] GetPrimaryKeyValues();
// 从数据源加载实体
void LoadFrom(IEntityDataSource source);
}
csharp
// 跨语言数据源接口
// C# 端适配 IDataReader
// Java 端适配 ResultSet
// ArkTS 端适配 relationalStore.ResultSet
public interface IEntityDataSource
{
object GetValue(string fieldName);
}
元数据提供方式(两种可选):
- 特性方式 :使用
[Table]、[Column]、[Key]等特性标记实体类,IMapEntity的实现通过反射读取。 - 手写方式 :实体类直接实现
IMapEntity接口,在GetFields()等方法中返回字段列表(兼容旧代码风格)。
例如
csharp
// 特性方式基类
[Table("Products")]
public class Product : AttributeMapEntity<Product>
{
[Column("Id")]
[Key]
public string Id { get; set; }
[Column("Name")]
public string Name { get; set; }
}
// 手写方式基类
public class Product : ManualMapEntity<Product>
{
public string Id { get; set; }
public string Name { get; set; }
protected override string[] GetFieldsCore()
{
return new string[] { "Id", "Name" };
}
protected override object[] GetFieldValuesCore()
{
return new object[] { Id, Name };
}
}
### 2. 实体存取接口 `IMap
EntityAccess`
定义对单个实体类型的增删改查操作:
csharp
public interface IMapEntityAccess<TEntity> where TEntity : class, IMapEntity<string>
{
// 当前实体实例
TEntity Entity { get; set; }
// 增删改查
int Insert();
int Update();
int Delete();
bool FillByPK(); // 根据主键填充当前实体
}
3. 基类 MapEntityAccessBase<TEntity>
实现 IMapEntityAccess<TEntity>,提供默认行为:
- 通过构造函数注入
IDataAccessExecutor(复用框架底层)及非特定语言的IEntityDataSource - 内部使用
CommandTextBuilder(见下文)根据实体元数据自动生成 SQL - 执行 SQL 时自动处理参数顺序(先字段值,后主键值,确保
UPDATE语句正确) - 注意 :每个操作前后不再使用 C# 的
event/delegate机制,改用虚方法钩子(OnBeforeInsert、OnAfterInserted等),确保 Java/ArkTS 端通过继承重写即可获得完全一致的扩展能力 - 引用
IUserBaoException实现跨语言异常隔离
csharp
public abstract class MapEntityAccessBase<TEntity> : IMapEntityAccess<TEntity>
where TEntity : class, IMapEntity<string>
{
// 构造函数:注入 IEntityDataSource 和 IDataAccessExecutor
protected MapEntityAccessBase(IEntityDataSource dataSource, IDataAccessExecutor executor)
{
}
// 实现接口
public TEntity Entity { get; set; }
public int Insert() { }
public int Update() { }
public int Delete() { }
public bool FillByPK() { }
// 钩子方法(虚方法,子类可重写)
// 返回 bool:true 继续执行,false 取消当前操作
protected virtual bool OnBeforeInsert()
{
return true;
}
protected virtual bool OnAfterInserted()
{
return true;
}
protected virtual bool OnBeforeUpdate()
{
return true;
}
protected virtual bool OnAfterUpdated()
{
return true;
}
protected virtual bool OnBeforeDelete()
{
return true;
}
protected virtual bool OnAfterDeleted()
{
return true;
}
protected virtual bool OnError(IUserBaoException ex)
{
return false;
}
// 内部 SQL 拼装器
private static class CommandTextBuilder
{
// ...
}
}
所有操作钩子统一行为:返回 true 继续流程,false 中断后续操作。这个改动将保留到后续的ORM扩展设计总结中。
设计要点:
- 钩子方法采用标准块体写法(
{ return true; }),三端可直接拷贝 - 虚方法重载在 C#/Java/ArkTS 中写法基本一致,是跨语言扩展点的最佳实践
- 不使用 C# 的
=>箭头表达式,避免三端语法差异
4. 内部类 CommandTextBuilder
仅供 MapEntityAccessBase 内部使用,不对外公开。
- 根据表名、字段列表、主键列表生成
INSERT/UPDATE/DELETE/SELECT模板 - 参数占位符统一用
@字段名(不区分数据库),最终由IDataAccessExecutor自动适配方言 UPDATE语句自动排除主键字段(主键不作为SET子句)- 提供参数列表生成方法(区分普通字段与主键字段,保证顺序正确)
四、与现有架构的集成点
- 数据执行 :
MapEntityAccessBase内部持有IDataAccessExecutor,通过它执行所有 SQL,自动获得方言适配、连接管理、事务支持。 - 事务管理 :开发者在使用
IMapEntityAccess时,外部用IUnitOfWork包围,即可实现多实体事务(与现有Repository方式一致)。 - 服务层 :
MapEntityAccessBase可以作为服务层的基础,也可以与现有ServiceBase协同使用(例如在 Service 中调用IMapEntityAccess)。
五、扩展点设计(虚方法钩子,而非事件委托)
每个操作(Insert / Update / Delete)前后均提供虚方法钩子,供子类重写:
五、扩展点设计(虚方法钩子,而非事件委托)
每个操作(Insert / Update / Delete)前后均提供虚方法钩子,供子类重写:
所有钩子统一返回 bool,含义如下:
| 返回值 | 含义 |
|---|---|
true |
继续执行后续流程 |
false |
中断后续操作 |
各钩子触发时机与用途:
| 钩子方法 | 触发时机 | 返回 false 的效果 |
|---|---|---|
OnBeforeInsert() |
执行 INSERT 前 | 取消本次插入 |
OnAfterInserted() |
INSERT 成功后 | 阻止后续提交或后续处理 |
OnBeforeUpdate() |
执行 UPDATE 前 | 取消本次更新 |
OnAfterUpdated() |
UPDATE 成功后 | 阻止后续提交或后续处理 |
OnBeforeDelete() |
执行 DELETE 前 | 取消本次删除 |
OnAfterDeleted() |
DELETE 成功后 | 阻止后续提交或后续处理 |
OnError(IUserBaoException) |
发生异常时 | 阻止异常向外抛出(已处理) |
为什么用虚方法钩子,而不是 C# 的 event/delegate?
| 方式 | C# | Java | ArkTS | 三端一致性 |
|---|---|---|---|---|
event / delegate |
原生支持 | ❌ 无直接对应 | ❌ 无直接对应 | ❌ |
| 虚方法重载 | virtual |
原生支持 | 原生支持 | ✅ 写法基本一致 |
event/delegate 是 C# 特有语法,Java 和 ArkTS 没有直接对应。使用虚方法钩子,三端开发者都可以通过继承基类、重写方法来实现完全相同的扩展逻辑,代码可以直接拷贝,只需调整语法格式。
为什么后置钩子也返回 bool?
前置钩子返回 false 可以取消操作(如参数校验不通过),后置钩子返回 false 同样有意义------例如插入成功后检查返回结果,发现异常需要阻止后续提交;或者删除成功后触发某些业务逻辑失败,需要中断后续流程。统一返回 bool 让所有扩展点都具备"继续/中断"的控制能力,灵活性更高。
业务方可以通过重写钩子实现:
- 操作前校验(如权限检查、字段自动填充)
- 操作后日志记录、缓存刷新
- 操作后条件判断,决定是否继续提交
- 取消操作(通过返回
false) - 异常处理与恢复
六、跨语言设计约束(重要)
为保持用宝框架"一次书写,三端复用"的核心能力,ORM 模块必须遵守:
| 禁止使用 | 应使用 | 原因 |
|---|---|---|
IList<T> / List<T> |
T[](数组) |
数组在 C#、Java、ArkTS 中都是原生语法 |
IDictionary<TKey,TValue> |
简单类型或数组 | 跨语言边界尽量用简单类型 |
| LINQ 表达式 | 直接代码逻辑 | LINQ 在 Java/ArkTS 中无直接对应 |
动态类型(dynamic) |
强类型或 object |
Java/ArkTS 不支持动态 |
event / delegate |
虚方法钩子 | event/delegate 是 C# 特有语法 |
=> 箭头表达式 |
标准块体 { return ...; } |
避免三端语法差异 |
所有接口定义、方法签名、属性类型必须使用跨语言原生类型。
七、注意事项与边界
- 此模块为可选扩展 ,不影响现有
UserBaoTech.Foundation核心基架。 - 不兼容旧代码,但借鉴旧设计思想(虚方法钩子、参数顺序处理)。
- 主键类型默认
string(GUID),但IMapEntity<TKey>支持泛型主键类型。 - 复合主键 :
PrimaryKeys支持多个字段,GetPrimaryKeyValues()返回对应顺序的值。 - SQL 生成:所有 SQL 均使用参数化查询,防止注入。
- 所有集合返回类型使用
T[],保持跨语言一致性。
八、对新 AI 的生成指令
基于以上设计,请生成 UserBaoTech.Foundation.ORM 命名空间下的完整代码文件:
IMapEntity.cs(接口定义,所有集合类型用T[])IMapEntityAccess.cs(接口定义)MapEntityAccessBase.cs(基类实现,含CommandTextBuilder内部类,所有集合类型用T[],无 event/delegate,钩子用虚方法)- 示例实体
Product展示特性标记方式(用于测试,不强制)
生成时遵循用宝框架风格:
- 使用 .NET Standard 2.0
- 无第三方依赖
- 所有集合返回类型使用
T[],保持跨语言一致性 - 方法命名清晰,注释完整
- 不使用
event/delegate,扩展点用虚方法钩子 - 不使用
=>箭头表达式,用标准块体写法 - 内部
CommandTextBuilder的参数占位符处理与DataAccessExecutor的方言适配兼容 - 错误处理引用
IUserBaoException,不暴露 C# 特有的Exception类型
反馈与交流 :欢迎在评论区留言或私信交流。如果你正在寻找一套 不用 EF、不用 Dapper、可跨语言迁移 的轻量级基架,用宝框架或许是一个值得尝试的选择。
用宝框架,拥抱第一 · 一次书写 · 三端复用------不仅是用户的朋友,而且是用户的宝贝