基于NET 6.0的自研轻量级ORM框架有哪些特点?

2026-05-23 00:251阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2482个文字,预计阅读时间需要10分钟。

Fast Framework 作者:Mr-zhong邮箱:850856667@qq.comQQ群:693979005开源地址:https://gitee.com/China-Mr-zhong/Fast.Framework前言:为了实现快速开发,省去编写大量Sql时间,更好地面向对象编程,因此诞生了Fast。

Fast Framework

Author Mr-zhong

Email 850856667@qq.com

QQ群 693979005

Open Source gitee.com/China-Mr-zhong/Fast.Framework

前言

为了实现快速开发,省去编写大量Sql时间,更好的面向对象编程由此诞生了 Fast Framework

Fast Framework 是一个基于NET6.0 封装的轻量级 ORM 框架 支持数据库 SqlServer Oracle MySql PostgreSql Sqlite 由于底层使用System.Data.Common 抽象类封装 理论支持所有Ado.Net 实现的类库,差异部分可能需要额外处理。

优点: 体积小、流畅API、性能高、简单易用、表达式树智能解析 缺点:不具备有自动建库建表、数据迁移等复杂的功能 由于不同数据库差异较大 实现较为复杂 所以暂时不考虑实现

项目明细
  1. Fast.Framework
  2. Fast.Framework.CustomAttribute
  3. Fast.Framework.Extensions
  4. Fast.Framework.Interfaces
  5. Fast.Framework.Logging
  6. Fast.Framework.Models
  7. Fast.Framework.Utils
快速入门

手动创建

var options = new DbOptions() //数据库选项 { DbType = DbType.MySQL, ProviderName = "MySqlConnector", FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector", ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout =30;AllowLoadLocalInfile=True;" }; var ado = new Ado(options);//原生Ado var db = new DbContext(options);//数据库上下文

依赖注入

var builder = WebApplication.CreateBuilder(args); // 正式项目请用配置文件注入,为了测试方便直接引用实现类库 builder.Services.AddScoped<IDbContext, DbContext>(); //加载Json配置文件 使用Net自带容器只能注入List<DbOptions> builder.Services.Configure<List<DbOptions>>(configuration.GetSection("DbConfig")); 特性支持

原生支持微软封装好的特性,命名空间如下

using System.ComponentModel.DataAnnotations.Schema;

using System.ComponentModel.DataAnnotations;

  • 示例

    /// <summary> /// 产品模型 /// </summary> [Table("Product")] public class ProductModel { [Key] public int ProductId { get; set; } /// <summary> /// 分类ID /// </summary> public int CategoryId { get; set; } /// <summary> /// 产品编号 /// </summary> public string ProductCode { get; set; } /// <summary> /// 产品名称 /// </summary> public string ProductName { get; set; } /// <summary> /// 创建日期 /// </summary> public DateTime CreateDate { get; set; } /// <summary> /// 是否删除 /// </summary> public bool IsDelete { get; set; } }

插入

实体对象插入

var product = new ProductModel() { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).ExecuteAsync();

实体对象插入并返回自增ID 仅支持 SQLServer MySQL SQLite

var product = new ProductModel() { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).ExecuteReturnIdentityAsync();

实体对象列表 批量插入

var list = new List<ProductModel>() { new ProductModel() { CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new ProductModel() { CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Insert(list).ExecuteAsync();

匿名对象插入 需要使用As方法显示指定表名称 如需返回自增ID 同上

var product = new { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).As("Product").ExecuteAsync();

匿名对象列表批量插入

var list = new List<object>() { new { CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new { CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Insert(list).As("Product").ExecuteAsync();

字典插入 注意需要显示使用 <类型> 否则将无法重载到正确的方法

var data = new Dictionary<string, object>() { { "ProductCode","1001"}, { "ProdutName","测试产品1"}, { "CategoryId",1}, { "CreateDate",DateTime.Now} }; var result = await db.Insert<ProductModel>(data).ExecuteAsync(); 删除

实体对象无条件删除

var result = await db.Delete<ProductModel>().ExecuteAsync();

实体对象条件删除

var result = await db.Delete<ProductModel>().Where(p => p.ProductId == 1).ExecuteAsync();

无实体删除 无条件删除场景很有用,特别用法

var result = await db.Delete<object>().As("Product").ExecuteAsync(); 更新

实体对象更新 如果只是更新一条数据请务必带上Where条件

var product = new ProductModel() { ProductCode = "1001", ProductName = "测试产品1" }; var result = await db.Update(product).Where(p => p.ProductId == 1).ExecuteAsync();

实体对象表达式更新 如果只是更新一条数据请务必带上Where条件

var result = await db.Update<ProductModel>(p => new ProductModel { ProductCode = "1001", ProductName = p.ProductCode + p.ProductName }).Where(p => p.ProductId == 1).ExecuteAsync();

实体对象列表 批量更新 默认会查找标注主键属性作为更新条件 如果没有主键 需要显示使用Where 方法指定条件列名称

var list = new List<ProductModel>() { new ProductModel() { ProductId=1, CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new ProductModel() { ProductId=2, CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Update(list).ExecuteAsync();

匿名对象更新 需要使用As方法显示指定表名称 如果只是更新一条数据请务必带上Where条件

var product = new { ProductCode = "1001", ProductName = "测试产品1" }; var result = await db.Update(product).As("product").Where(p => p.ProductId == 1).ExecuteAsync();

字典更新 注意需要显示使用 <类型> 否则将无法重载到正确的方法

var data = new Dictionary<string, object>() { { "ProductCode","1001"}, { "ProdutName","测试产品1"}, { "CategoryId",1}, { "CreateDate",DateTime.Now} }; var result = await db.Update<ProductModel>(data).Where(p => p.ProductId == 1).ExecuteAsync(); 查询

单一对象

var data = await db.Query<ProductModel>().FirstAsync();

列表

var data = await db.Query<ProductModel>().ToListAsync();

分页

var pageData = await db.Query<ProductModel>().ToPageListAsync(1, 10);

单个字典

var data = await db.Query<ProductModel>().DictionaryAsync();

字典列表

var data = await db.Query<ProductModel>().DictionaryListAsync();

查询并插入 同表复制数据或者跨表复制数据将非常有用

var result = await db.Query<ProductModel>().Where(p => p.ProductId == 1).Select(p => new { CategoryId = 2, p.ProductCode, p.ProductName }).Insert<ProductModel>(p => new { p.CategoryId, p.ProductCode, p.ProductName }).ExecuteAsync();// 需要调用ExecuteAsync 才会执行并返回受影响行数

计数

var count = await db.Query<ProductModel>().CountAsync();

任何

var count = await db.Query<ProductModel>().AnyAsync();

条件

var data = await db.Query<ProductModel>().Where(p => p.IsDelete == true).ToListAsync();

In 有好几个重载方法 不全部列出

var data = await db.Query<ProductModel>().In(p => p.ProductId, ids).ToListAsync();

NotIn 有好几个重载方法 不全部列出

var data = await db.Query<ProductModel>().NotIn(p => p.ProductId, ids).ToListAsync();

分组

var data = await db.Query<ProductModel>().GroupBy(p => new { p.ProductCode, p.ProductName }).ToListAsync();

HavaVing 需要和GroupBy 组合

var data = await db.Query<ProductModel>().GroupBy(p => new { p.ProductCode, p.ProductName }).Having(p => SqlFunc.Count(1) > 1).ToListAsync();

排序 默认ASC 升序

var data = await db.Query<ProductModel>().OrderBy(o => new { o.ProductId }, "DESC").ToListAsync();

并集 多个查询合并成一个 列名个数和数据类型需要一一对应

var query1 = db.Query<ProductModel>().Select(s => new { s.ProductCode, s.ProductName }); var query2 = db.Query<ProductModel>().Select(s => new { s.ProductCode, s.ProductName }); var data = db.Union(query1, query2).ToListAsync();

左连接

var data = db.Query<ProductModel>() .LeftJoin<ProductCategoryModel>((p, c) => p.CategoryId == c.CategoryId) .Select((p, c) => new { c.CategoryName, p.ProductCode, p.ProductName }).ToListAsync();

内连接

var data = db.Query<ProductModel>() .InnerJoin<ProductCategoryModel>((p, c) => p.CategoryId == c.CategoryId) .Select((p, c) => new { c.CategoryName, p.ProductCode, p.ProductName }).ToListAsync();

选择 返回指定字段

var data = db.Query<ProductModel>().Select(p => new { p.ProductCode, p.ProductName }).ToListAsync();

模糊查询 StartsWith 左模糊 EndsWith 右模糊 Contains 全模糊

var data = db.Query<ProductModel>().Where(p => p.ProductName.Contains("测试")).ToListAsync();

动态条件表达式

var ex = DynamicWhereExpression.Create<ProductModel>(); // 两个子表达式参数名 p 必须一致 ex.AndIF(1 == 1, p => p.ProductCode == "1001"); ex.AndIF(1 == 1, p => p.ProductName == "测试"); var data = db.Query<ProductModel>().Where(ex.Build()).ToListAsync(); 函数类

Fast.Framework.SqlFunc.cs

Fast.Framework.Extensions.SqlFuncExtensionscs.cs

对比两种使用方式 两种方式是等价的 我更喜欢使用扩展方法

var data = db.Query<ProductModel>().Select(s => new { Case1 = 1.Count(), Case2 = SqlFunc.Count(1) }).ToListAsync();

特殊方法Call 如果您需要在表达式new一个对象调用方法或者获取属性值 需要显示调用这个方法 因为表达式默认解析类型是SqlString

var data = db.Query<ProductModel>().Where(p => p.ProductCode == new { ProductCode = "123" }.Call().ProductCode).ToListAsync(); 输出Sql

  • 使用Tostring() Insert Delete Update Query 对象都支持

var sql = db.Query<ProductModel>().ToString(); Console.WriteLine(sql);

  • 使用数据库日志委托

db.Aop.DbLog = (sql, parameters) => { Console.WriteLine($"ExecuteSql:{sql}"); if (parameters != null) { foreach (var item in parameters) { Console.WriteLine($"参数名:{item.ParameterName} 参数值:{item.Value}"); } } Console.WriteLine($"ExecuteTime:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); Console.WriteLine(); }; Ado 原生

如果DbContext 无法满足复杂查询需求 可以使用Ado原生满足各种复杂查询

// 这是一个简单的示例 仅供参考 var sql = "select * from product where productcode=@ProductCode;select 100;"; var paramters = new Dictionary<string, object>() { { "ProductCode","1001"} }; var reader = db.Ado.ExecuteReaderAsync(sql, db.Ado.SqlParametersBuild(paramters)); var data = await reader.ListBuildAsync<ProductModel>(); var count = await reader.FristBuildAsync<int>();

本文共计2482个文字,预计阅读时间需要10分钟。

Fast Framework 作者:Mr-zhong邮箱:850856667@qq.comQQ群:693979005开源地址:https://gitee.com/China-Mr-zhong/Fast.Framework前言:为了实现快速开发,省去编写大量Sql时间,更好地面向对象编程,因此诞生了Fast。

Fast Framework

Author Mr-zhong

Email 850856667@qq.com

QQ群 693979005

Open Source gitee.com/China-Mr-zhong/Fast.Framework

前言

为了实现快速开发,省去编写大量Sql时间,更好的面向对象编程由此诞生了 Fast Framework

Fast Framework 是一个基于NET6.0 封装的轻量级 ORM 框架 支持数据库 SqlServer Oracle MySql PostgreSql Sqlite 由于底层使用System.Data.Common 抽象类封装 理论支持所有Ado.Net 实现的类库,差异部分可能需要额外处理。

优点: 体积小、流畅API、性能高、简单易用、表达式树智能解析 缺点:不具备有自动建库建表、数据迁移等复杂的功能 由于不同数据库差异较大 实现较为复杂 所以暂时不考虑实现

项目明细
  1. Fast.Framework
  2. Fast.Framework.CustomAttribute
  3. Fast.Framework.Extensions
  4. Fast.Framework.Interfaces
  5. Fast.Framework.Logging
  6. Fast.Framework.Models
  7. Fast.Framework.Utils
快速入门

手动创建

var options = new DbOptions() //数据库选项 { DbType = DbType.MySQL, ProviderName = "MySqlConnector", FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector", ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout =30;AllowLoadLocalInfile=True;" }; var ado = new Ado(options);//原生Ado var db = new DbContext(options);//数据库上下文

依赖注入

var builder = WebApplication.CreateBuilder(args); // 正式项目请用配置文件注入,为了测试方便直接引用实现类库 builder.Services.AddScoped<IDbContext, DbContext>(); //加载Json配置文件 使用Net自带容器只能注入List<DbOptions> builder.Services.Configure<List<DbOptions>>(configuration.GetSection("DbConfig")); 特性支持

原生支持微软封装好的特性,命名空间如下

using System.ComponentModel.DataAnnotations.Schema;

using System.ComponentModel.DataAnnotations;

  • 示例

    /// <summary> /// 产品模型 /// </summary> [Table("Product")] public class ProductModel { [Key] public int ProductId { get; set; } /// <summary> /// 分类ID /// </summary> public int CategoryId { get; set; } /// <summary> /// 产品编号 /// </summary> public string ProductCode { get; set; } /// <summary> /// 产品名称 /// </summary> public string ProductName { get; set; } /// <summary> /// 创建日期 /// </summary> public DateTime CreateDate { get; set; } /// <summary> /// 是否删除 /// </summary> public bool IsDelete { get; set; } }

插入

实体对象插入

var product = new ProductModel() { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).ExecuteAsync();

实体对象插入并返回自增ID 仅支持 SQLServer MySQL SQLite

var product = new ProductModel() { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).ExecuteReturnIdentityAsync();

实体对象列表 批量插入

var list = new List<ProductModel>() { new ProductModel() { CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new ProductModel() { CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Insert(list).ExecuteAsync();

匿名对象插入 需要使用As方法显示指定表名称 如需返回自增ID 同上

var product = new { CategoryId = 1, ProductCode = "1001", ProductName = "测试产品1", CreateDate = DateTime.Now }; var result = await db.Insert(product).As("Product").ExecuteAsync();

匿名对象列表批量插入

var list = new List<object>() { new { CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new { CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Insert(list).As("Product").ExecuteAsync();

字典插入 注意需要显示使用 <类型> 否则将无法重载到正确的方法

var data = new Dictionary<string, object>() { { "ProductCode","1001"}, { "ProdutName","测试产品1"}, { "CategoryId",1}, { "CreateDate",DateTime.Now} }; var result = await db.Insert<ProductModel>(data).ExecuteAsync(); 删除

实体对象无条件删除

var result = await db.Delete<ProductModel>().ExecuteAsync();

实体对象条件删除

var result = await db.Delete<ProductModel>().Where(p => p.ProductId == 1).ExecuteAsync();

无实体删除 无条件删除场景很有用,特别用法

var result = await db.Delete<object>().As("Product").ExecuteAsync(); 更新

实体对象更新 如果只是更新一条数据请务必带上Where条件

var product = new ProductModel() { ProductCode = "1001", ProductName = "测试产品1" }; var result = await db.Update(product).Where(p => p.ProductId == 1).ExecuteAsync();

实体对象表达式更新 如果只是更新一条数据请务必带上Where条件

var result = await db.Update<ProductModel>(p => new ProductModel { ProductCode = "1001", ProductName = p.ProductCode + p.ProductName }).Where(p => p.ProductId == 1).ExecuteAsync();

实体对象列表 批量更新 默认会查找标注主键属性作为更新条件 如果没有主键 需要显示使用Where 方法指定条件列名称

var list = new List<ProductModel>() { new ProductModel() { ProductId=1, CategoryId=1, ProductCode="1001", ProductName="测试产品1", CreateDate=DateTime.Now }, new ProductModel() { ProductId=2, CategoryId=1, ProductCode="1002", ProductName="测试产品2", CreateDate=DateTime.Now, } }; var result = await db.Update(list).ExecuteAsync();

匿名对象更新 需要使用As方法显示指定表名称 如果只是更新一条数据请务必带上Where条件

var product = new { ProductCode = "1001", ProductName = "测试产品1" }; var result = await db.Update(product).As("product").Where(p => p.ProductId == 1).ExecuteAsync();

字典更新 注意需要显示使用 <类型> 否则将无法重载到正确的方法

var data = new Dictionary<string, object>() { { "ProductCode","1001"}, { "ProdutName","测试产品1"}, { "CategoryId",1}, { "CreateDate",DateTime.Now} }; var result = await db.Update<ProductModel>(data).Where(p => p.ProductId == 1).ExecuteAsync(); 查询

单一对象

var data = await db.Query<ProductModel>().FirstAsync();

列表

var data = await db.Query<ProductModel>().ToListAsync();

分页

var pageData = await db.Query<ProductModel>().ToPageListAsync(1, 10);

单个字典

var data = await db.Query<ProductModel>().DictionaryAsync();

字典列表

var data = await db.Query<ProductModel>().DictionaryListAsync();

查询并插入 同表复制数据或者跨表复制数据将非常有用

var result = await db.Query<ProductModel>().Where(p => p.ProductId == 1).Select(p => new { CategoryId = 2, p.ProductCode, p.ProductName }).Insert<ProductModel>(p => new { p.CategoryId, p.ProductCode, p.ProductName }).ExecuteAsync();// 需要调用ExecuteAsync 才会执行并返回受影响行数

计数

var count = await db.Query<ProductModel>().CountAsync();

任何

var count = await db.Query<ProductModel>().AnyAsync();

条件

var data = await db.Query<ProductModel>().Where(p => p.IsDelete == true).ToListAsync();

In 有好几个重载方法 不全部列出

var data = await db.Query<ProductModel>().In(p => p.ProductId, ids).ToListAsync();

NotIn 有好几个重载方法 不全部列出

var data = await db.Query<ProductModel>().NotIn(p => p.ProductId, ids).ToListAsync();

分组

var data = await db.Query<ProductModel>().GroupBy(p => new { p.ProductCode, p.ProductName }).ToListAsync();

HavaVing 需要和GroupBy 组合

var data = await db.Query<ProductModel>().GroupBy(p => new { p.ProductCode, p.ProductName }).Having(p => SqlFunc.Count(1) > 1).ToListAsync();

排序 默认ASC 升序

var data = await db.Query<ProductModel>().OrderBy(o => new { o.ProductId }, "DESC").ToListAsync();

并集 多个查询合并成一个 列名个数和数据类型需要一一对应

var query1 = db.Query<ProductModel>().Select(s => new { s.ProductCode, s.ProductName }); var query2 = db.Query<ProductModel>().Select(s => new { s.ProductCode, s.ProductName }); var data = db.Union(query1, query2).ToListAsync();

左连接

var data = db.Query<ProductModel>() .LeftJoin<ProductCategoryModel>((p, c) => p.CategoryId == c.CategoryId) .Select((p, c) => new { c.CategoryName, p.ProductCode, p.ProductName }).ToListAsync();

内连接

var data = db.Query<ProductModel>() .InnerJoin<ProductCategoryModel>((p, c) => p.CategoryId == c.CategoryId) .Select((p, c) => new { c.CategoryName, p.ProductCode, p.ProductName }).ToListAsync();

选择 返回指定字段

var data = db.Query<ProductModel>().Select(p => new { p.ProductCode, p.ProductName }).ToListAsync();

模糊查询 StartsWith 左模糊 EndsWith 右模糊 Contains 全模糊

var data = db.Query<ProductModel>().Where(p => p.ProductName.Contains("测试")).ToListAsync();

动态条件表达式

var ex = DynamicWhereExpression.Create<ProductModel>(); // 两个子表达式参数名 p 必须一致 ex.AndIF(1 == 1, p => p.ProductCode == "1001"); ex.AndIF(1 == 1, p => p.ProductName == "测试"); var data = db.Query<ProductModel>().Where(ex.Build()).ToListAsync(); 函数类

Fast.Framework.SqlFunc.cs

Fast.Framework.Extensions.SqlFuncExtensionscs.cs

对比两种使用方式 两种方式是等价的 我更喜欢使用扩展方法

var data = db.Query<ProductModel>().Select(s => new { Case1 = 1.Count(), Case2 = SqlFunc.Count(1) }).ToListAsync();

特殊方法Call 如果您需要在表达式new一个对象调用方法或者获取属性值 需要显示调用这个方法 因为表达式默认解析类型是SqlString

var data = db.Query<ProductModel>().Where(p => p.ProductCode == new { ProductCode = "123" }.Call().ProductCode).ToListAsync(); 输出Sql

  • 使用Tostring() Insert Delete Update Query 对象都支持

var sql = db.Query<ProductModel>().ToString(); Console.WriteLine(sql);

  • 使用数据库日志委托

db.Aop.DbLog = (sql, parameters) => { Console.WriteLine($"ExecuteSql:{sql}"); if (parameters != null) { foreach (var item in parameters) { Console.WriteLine($"参数名:{item.ParameterName} 参数值:{item.Value}"); } } Console.WriteLine($"ExecuteTime:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); Console.WriteLine(); }; Ado 原生

如果DbContext 无法满足复杂查询需求 可以使用Ado原生满足各种复杂查询

// 这是一个简单的示例 仅供参考 var sql = "select * from product where productcode=@ProductCode;select 100;"; var paramters = new Dictionary<string, object>() { { "ProductCode","1001"} }; var reader = db.Ado.ExecuteReaderAsync(sql, db.Ado.SqlParametersBuild(paramters)); var data = await reader.ListBuildAsync<ProductModel>(); var count = await reader.FristBuildAsync<int>();