一、前言
Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer Oracle MySql PostgreSql Sqlite
优点: 体积小、可动态切换不同实现类库、原生支持微软特性、流畅API、使用简单、性能高、模型数据绑定采用Emit、强大的表达式解析、支持多种子查询可实现较为复杂查询、源代码可读性强。
缺点:目前仅支持Db Frist Code Frist 后续迭代。
开源地址:https://github.com/China-Mr-zhong/Fast-Framework (唯一)
多个生产项目稳定运行中
二、项目明细
| 名称 | 说明 | 
|---|---|
| Fast.Framework | ORM | 
| Fast.Framework.Logging | 文件日志 (扩展项目可不使用) | 
| Fast.Framework.DependencyInjection | 依赖注入 (扩展项目可不使用) | 
| Fast.Framework.Test | 控制台测试项目 | 
| Fast.Framework.UnitTest | 单元测试项目 | 
| Fast.Framework.Web.Test | Web测试项目 | 
三、核心对象
- Ado - IAdo ado = new AdoProvider(new DbOptions() { DbId = "1", 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;" });
- DbContext 支持多租户 支持切换不同Ado实现类库 设置 ProviderName和FactoryName 即可 - IDbContext db = new DbContext(new List<DbOptions>() { new DbOptions() { DbId = "1", 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;" }});
- DbOptions Json文件配置格式 - "DbOptions": [ { "DbId": 1, "DbType": "SQLServer", "ProviderName": "System.Data.SqlClient", "FactoryName": "System.Data.SqlClient.SqlClientFactory,System.Data", "ConnectionStrings": "server=localhost;database=Test;user=sa;pwd=123456789;min pool size=3;max pool size=100;connect timeout=120;" }]
- 主从分离(读写分离)配置 - "DbOptions": [ { "DbId": 2, "DbType": "MySQL", "IsDefault": true, "ProviderName": "MySqlConnector", "FactoryName": "MySqlConnector.MySqlConnectorFactory,MySqlConnector", "ConnectionStrings": "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=0;max pool size=100;connect timeout=120;AllowLoadLocalInfile=true;", "UseMasterSlaveSeparation": true,//使用主从分离 注意所有事务将强制走主库 "SlaveItems": [ { "Weight": 1,//注意多个从库 必须配置权重且总权重>从库数 "ConnectionStrings": "server=localhost;database=Test1;user=root;pwd=123456789;port=3306;min pool size=0;max pool size=100;connect timeout=120;AllowLoadLocalInfile=true;", "Description": "从库连接配置" }, { "Weight": 2, "ConnectionStrings": "server=localhost;database=Test2;user=root;pwd=123456789;port=3306;min pool size=0;max pool size=100;connect timeout=120;AllowLoadLocalInfile=true;", "Description": "从库连接配置" } ], "Description": "主库连接配置" } ]
- Asp.net Core 依赖注入 - // 注册服务 var builder = WebApplication.CreateBuilder(args);// 添加数据库上下文builder.Services.AddFastDbContext();// 从Json配置文件加载数据库选项builder.Services.Configure<List<DbOptions>>(builder.Configuration.GetSection("DbOptions"));// 产品服务类 通过构造方法注入public class ProductService{ /// <summary> /// 数据库 /// </summary> private readonly IDbContext db; /// <summary> /// 构造方法 /// </summary> /// <param name="db">数据库</param> public ProductService(IDbContext db) { this.db = db; } }
四、插入
- 实体对象插入 - var product = new Product() { ProductCode = "1001", ProductName = "测试商品1" }; var result = db.Insert(product).Exceute();
- 实体对象插入并返回自增ID 仅支持 SQLServer MySQL SQLite - var product = new Product() { ProductCode = "1001", ProductName = "测试产品1" }; var result = db.Insert(product).ExceuteReturnIdentity();
- 实体对象列表插入 - var list = new List<Product>(); for (int i = 0; i < 2100; i++) { list.Add(new Product() { ProductCode = $"编号{i + 1}", ProductName = $"名称{i + 1}" }); } var result = db.Insert(list).Exceute();
- 匿名对象插入 - var obj = new { ProductCode = "1001", ProductName = "测试商品1" }; //注意:需要使用As方法显示指定表名称 var result = db.Insert(obj).As("Product").Exceute();
- 匿名对象列表插入 - var list = new List<object>(); for (int i = 0; i < 2100; i++) { list.Add(new { ProductCode = $"编号{i + 1}", ProductName = $"名称{i + 1}" }); } //注意:需要使用As方法显示指定表名称 var result = db.Insert(list).As("Product").Exceute();
- 字典插入 - var product = new Dictionary<string, object>() { {"ProductCode","1001"}, { "ProductName","测试商品1"} }; var result = db.Insert(product).As("Product").Exceute();
- 字典列表插入 - var list = new List<Dictionary<string, object>>(); for (int i = 0; i < 2100; i++) { list.Add(new Dictionary<string, object>() { {"ProductCode","1001"}, { "ProductName","测试商品1"} }); } var result = db.Insert(list).As("Product").Exceute();
五、删除
- 实体对象删除 - var product = new Product() { ProductId = 1, ProductCode = "1001", ProductName = "测试商品1" }; var result = db.Delete(product).Exceute();
- 实体对象列表删除 - var list = new List<Product>(); for (int i = 0; i < 2100; i++) { list.Add(new Product() { ProductCode = $"编号{i + 1}", ProductName = $"名称{i + 1}" }); } var result = db.Delete(list).Exceute();
- 无条件删除 - var result = db.Delete<Product>().Exceute();
- 条件删除 - var result = await db.Delete<Product>().Where(w => w.ProductId == 1).ExceuteAsync();
- 逻辑删除 - /* 可用特性标记逻辑删除列 仅支持 int bool datetime 类型,其它类型不合适 /// <summary> /// 删除标记 /// </summary> [Logic] public bool DeleteMark { get; set; } */ //额外设置其它属性值,使用SetColumns方法前需先使用IsLogic方法 //类型逻辑删除 var result1 = db.Delete<Product>().IsLogic().SetColumns(c => new Product() { ModifyTime = DateTime.Now }).Where(w => w.ProductId == 1).Exceute(); //对象逻辑删除 var result2 = db.Delete(new Product() { ProductId = 1 }).IsLogic().SetColumns(c => new Product() { ModifyTime = DateTime.Now }).Exceute(); //特殊逻辑删除(不想建实体类可以用该方式) var result3 = db.Delete<object>().As("Product").IsLogic().SetColumns(c => new { ModifyTime = DateTime.Now }).Exceute();
- 特殊删除 - //特殊用法 如需单个条件或多个可搭配 Where或WhereColumns方法 var result = await db.Delete<object>().As("Product").ExceuteAsync(); Console.WriteLine($"无实体删除 受影响行数 {result}");
六、更新
- 实体对象更新 - var product = new Product() { ProductId = 1, ProductCode = "1001", ProductName = "测试商品1" }; //注意:标记KeyAuttribute特性属性或使用Where条件,为了安全起见全表更新将必须使用Where方法 var result = db.Update(product).Exceute();
- 指定列更新 - var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).Columns(c=> new { c.ProductCode , c.ProductName }).Exceute(); // 推荐使用表达式 c=>new {} 好处更改属性名称可以同步修改
- 忽略列更新 - var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).IgnoreColumns(c=> new { c.Custom1 }).Exceute(); // 同上使用方法一样
- 实体对象列表更新 - var list = new List<Product>(); for (int i = 0; i < 2022; i++) { list.Add(new Product() { ProductCode = $"编号{i + 1}", ProductName = $"名称{i + 1}" }); } //注意:标记KeyAuttribute特性属性或使用WhereColumns方法指定更新条件列 var result = db.Update(list).Exceute();
- 匿名对象更新 - var obj = new { ProductId = 1, ProductCode = "1001", ProductName = "测试商品1" }; //注意:需要显示指定表名称 以及更新条件 使用 Where或者WhereColumns方法均可 var result = db.Update(obj).As("product").WhereColumns("ProductId").Exceute();
- 匿名对象列表更新 - var list = new List<object>(); for (int i = 0; i < 2022; i++) { list.Add(new { ProductId = i + 1, ProductCode = $"编号{i + 1}", ProductName = $"名称{i + 1}" }); } //由于是匿名对象需要显示指定表名称,使用WhereColumns方法指定更新条件列 var result = db.Update(list).As("Product").WhereColumns("ProductId").Exceute();
- 字典更新 - var product = new Dictionary<string, object>() { { "ProductId",1}, {"ProductCode","1001"}, { "ProductName","测试商品1"} }; var result = db.Update(product).As("Product").WhereColumns("ProductId").Exceute();
- 字典列表更新 - var list = new List<Dictionary<string, object>>(); for (int i = 0; i < 2022; i++) { list.Add(new Dictionary<string, object>() { { "ProductId",i+1}, {"ProductCode",$"更新编号:{i+1}"}, { "ProductName",$"更新商品:{i + 1}"} }); } var result = db.Update(list).As("Product").WhereColumns("ProductId").Exceute();
- 设置列更新 - // 设置列更新 db.Update<Product>().SetColumns(c => new Product() { ProductCode = "1001", ProductName = "测试产品1" }).Where(w => w.ProductId == 1).Exceute();
- 指定条件更新 - var product = new Product() { ProductId = 1, ProductCode = "1001", ProductName = "测试商品1" }; var result = db.Update(product).Where(p => p.ProductId == 100).Exceute(); Console.WriteLine($"表达式更新 受影响行数 {result}");
- 并发更新 乐观锁-版本控制 - //注意:仅支持非列表更新 版本列数据类型仅支持 object、string、Guid 时间类型存在精度丢失所以不做支持 var obj = db.Query<Product>().Where(w => w.ProductId == 1).Frist(); obj.Custom1 = "测试版本控制修改"; //参数为 true 更新失败将抛出异常 var result = db.Update(obj).ExceuteWithOptLock(true);
七、查询
- 单一查询 - var data = db.Query<Product>().First();
- 列表查询 - var data = db.Query<Product>().ToList();
- 返回单个字典 - var data = db.Query<Product>().ToDictionary();
- 返回字典列表 - var data = db.Query<Product>().ToDictionaryList();
- 分页查询 - //分页查询不返回总数 var data = db.Query<Product>().ToPageList(1,100); //分页查询返回总数 var total = 0;//定义总数变量 var data = db.Query<Product>().ToPageList(1, 1, ref total); Console.WriteLine($"总数:{total}");
- 计数查询 - var data = db.Query<Product>().Count();
- 任何查询 - var data = db.Query<Product>().Any();
- 条件查询 - var data = db.Query<Product>().Where(w => w.ProductId == 1).ToList;
- Like 查询 - var data = db.Query<Product>().Where(w => w.ProductName.StartsWith("左模糊") || w.ProductName.EndsWith("右模糊") || w.ProductName.Contains("全模糊")).ToList();
- Not Like查询 - var data = db.Query<Product>().Where(w => !w.ProductName.StartsWith("左模糊") || !w.ProductName.EndsWith("右模糊") || !w.ProductName.Contains("全模糊")).ToList();
- Select查询 (选择字段) - var data = db.Query<Product>().Select(s => new { s.ProductId, s.ProductName }).ToList();
- Select查询 (Case When) - var data = db.Query<Product>().Select(s => new { CaseTest1 = SqlFunc.Case(s.Custom1).When("1").Then("xx1").When("2").Then("xx2").Else("xx3").End(), CaseTest2 = SqlFunc.CaseWhen<string>(s.Custom1 == "1").Then("xx1").When(s.Custom1 == "2").Then("xx2").Else("xx3").End() }).ToList();
- 分组查询 - var data = db.Query<Product>().GroupBy(s => new { s.ProductId, s.ProductName }).ToList();
- 分组聚合查询 - var sql = db.Query<Order>().InnerJoin<OrderDetail>((a, b) => a.OrderId == b.OrderId).GroupBy((a, b) => new { a.OrderCode }).Select((a, b) => new { a.OrderCode, Sum_Qty = SqlFunc.Sum(b.Qty)//支持嵌套 }).ToList();
- 排序查询 - var data = db.Query<Product>().OrderBy(s => new { s.CreateTime }).ToList(); //这是多个字段排序使用方法 还有其它重载方法
- Having查询 - var data = db.Query<Product>().GroupBy(s => new { s.ProductId, s.ProductName }).Having(s => SqlFunc.Count(s.ProductId) > 1).ToList(); //必须先使用GroupBy方法 懂得都懂
- 联表查询 - var data = db.Query<Product>().LeftJoin<Class1>((a, b) => a.ProductId == b.ProductId).ToList(); // 右连接 RightJoin 内连接 InnerJoin 全连接 FullJoin
- 联合查询 - var query1 = db.Query<Product>(); var query2 = db.Query<Product>(); db.Union(query1, query2);//联合 db.UnionAll(query1, query2);//全联合 //执行查询调用Toxx方法
- 导航查询 (支持无限层级) - /// <summary> /// 类别 /// </summary> public class Category { /// <summary> /// 类别ID /// </summary> [Key] public int CategoryId { get; set; } /// <summary> /// 类别名称 /// </summary> public string CategoryName { get; set; } /// <summary> /// 产品 Navigate MainName和ChildName 可不显示指定,会自动查找主键匹配或ID为结尾的属性 /// </summary> [Navigate(MainName = nameof(CategoryId), ChildName = nameof(Product.CategoryId))] public IEnumerable<Product> Products { get; set; } } var data = db.Query<Category>() .Include(i => i.Products) .ToList();
- 查询并插入 仅支持同实例的数据库 跨库 个人还是建议 用事务分开写查询和插入 - //方式1 var result1 = db.Query<Product>().Where(w => w.ProductId == 1489087).Select(s => new { s.ProductCode, s.ProductName }).Insert<Product>(p => new { p.ProductCode, p.ProductName }); //方式2 var result2 = db.Query<Product>().Where(w => w.ProductId == 1489087).Select(s => new { s.ProductCode, s.ProductName }).Insert("表名称 同实例不同库 可以使用 db.数据库名称.表名称 ", "列名称1", "列名称2"); //方式3 需要注意同方式2 一样 var result3 = db.Query<Product>().Where(w => w.ProductId == 1489087).Select(s => new { s.ProductCode, s.ProductName }).Insert("表名称 同实例不同库 可以使用 db.数据库名称.表名称 ", new List<string>() { "列名称1" });
- In查询 - var data1 = db.Query<Product>().Where(w => new List<string>(){"1001", "1002"}.Contains(w.ProductCode)).ToList();
- Select嵌套查询和子查询 - var data1 = db.Query<Product>().Select(s => new { XX = db.Query<Product>().Select(s => 1).First()//需调用返回结果的方法 否则无法解析 }).First(); //进价用法,下面示例方法的重载均支持 var count = 0; var refAsync = new RefAsync<int>(); var query = db.Query<Product>().Select(s => new { WithAttr_First = db.QueryWithAttr<Product>().First(), WithAttr_FirstAsync = db.QueryWithAttr<Product>().FirstAsync(), WithAttr_ToList = db.QueryWithAttr<Product>().ToList(), WithAttr_ToListAsync = db.QueryWithAttr<Product>().ToListAsync(), First_1 = db.Query<Category>().Select(s => 1).First(),//解析成Sql First = db.Query<Category>().First(), FirstAsync = db.Query<Category>().FirstAsync(), ToArray = db.Query<Category>().ToArray(), ToArrayAsync = db.Query<Category>().ToArrayAsync(), ToList = db.Query<Category>().ToList(), ToListAsync = db.Query<Category>().ToListAsync(), ToPageList = db.Query<Category>().ToPageList(1, 10), ToPageListAsync = db.Query<Category>().ToPageListAsync(1, 10), ToPageList_Count = db.Query<Category>().ToPageList(1, 10, ref count), ToPageListAsync_Count = db.Query<Category>().ToPageListAsync(1, 10, refAsync), ToDictionary = db.Query<Category>().ToDictionary(), ToDictionaryAsync = db.Query<Category>().ToDictionaryAsync(), ToDictionaryList = db.Query<Category>().ToDictionaryList(), ToDictionaryListAsync = db.Query<Category>().ToDictionaryListAsync(), ToDictionaryPageList = db.Query<Category>().ToDictionaryPageList(1, 10), ToDictionaryPageListAsync = db.Query<Category>().ToDictionaryPageListAsync(1, 10), ToDictionaryPageList_Count = db.Query<Category>().ToDictionaryPageList(1, 10, ref count), ToDictionaryPageListAsync_Count = db.Query<Category>().ToDictionaryPageListAsync(1, 10, refAsync), ToDataTable = db.Query<Category>().ToDataTable(), ToDataTableAsync = db.Query<Category>().ToDataTableAsync(), ObjToJson = db.Query<Category>().ObjToJson(), ObjToJsonAsync = db.Query<Category>().ObjToJsonAsync(), ObjListToJson = db.Query<Category>().ObjListToJson(), ObjListToJsonAsync = db.Query<Category>().ObjListToJsonAsync(), Max = db.Query<Category>().Max(a => a.CategoryId),//解析成Sql MaxAsync = db.Query<Category>().MaxAsync(a => a.CategoryId), Min = db.Query<Category>().Min(a => a.CategoryId),//解析成Sql MinAsync = db.Query<Category>().MinAsync(a => a.CategoryId), Count = db.Query<Category>().Count(),//解析成Sql CountAsync = db.Query<Category>().CountAsync(), Sum = db.Query<Category>().Sum(s => s.CategoryId),//解析成Sql SumAsync = db.Query<Category>().SumAsync(s => s.CategoryId), Avg = db.Query<Category>().Avg(s => s.CategoryId),//解析成Sql AvgAsync = db.Query<Category>().AvgAsync(s => s.CategoryId) }); var data2= query.First();
- From子查询 - var subQuery2 = db.Query<Product>().Select(s=>new { s.ProductId, s.CategoryId, s.ProductCode, s.ProductName, s.DeleteMark }); var data = db.Query(subQuery2).ToList();
- Join子查询 - var subQuery1 = db.Query<Product>().Select(s => new { s.ProductId, s.CategoryId, s.ProductCode, s.ProductName, s.DeleteMark }); var data = db.Query<Category>().InnerJoin(subQuery1, (a, b) => a.CategoryId == b.CategoryId).ToList();
- Include查询 - // 联表条件 默认优先匹配主键 其次带有ID结尾的名称 var data = db.Query<Category>().Include(i => i.Products).ToList();
- Exists查询 - var data = db.Query<Product>() .Where(w => db.Query<Product>().WhereIF(!string.IsNullOrWhiteSpace("测试"), a => a.ProductId == 1).Select(s => 1).Any()) .Select(s => new { s.ProductId, s.ProductCode }).ToList();
- 查询绑定字段(注意 字段必须是公开的,否则绑定外部无法访问,没有意义) - //当某些字段需要参与计算并且不返回前端时推荐用字段绑定,无需从A实体转换到B实体,强烈推荐此方式 var data = db.Query<Product>().Select(s => new Product() { _xx = s.ProductName }).First();
八、Lambda表达式
- 动态表达式 命名空间 Fast.Framework.Utils - var ex = DynamicWhereExp.Create<Product>().AndIF(1 == 1, a => a.DeleteMark == true).Build(); var data = db.Query<Product>().Where(ex).ToList();
- Sql函数 自定义函数 需引入命名空间 Fast.Framework.Utils 使用SqlFunc类 - SqlServer - 类型转换 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - ToString - CONVERT( VARCHAR(255),123) - 转换 VARCHAR - 否 - ToDateTime - CONVERT( DATETIME,‘2022-09-16’) - 转换 DATETIME - 否 - ToDecimal - CONVERT( DECIMAL(10,6),‘123’) - 转换 DECIMAL - 否 - ToDouble - CONVERT( NUMERIC(10,6),‘123’) - 转换 NUMERIC - 否 - ToSingle - CONVERT( FLOAT,‘123’) - 转换 FLOAT - 否 - ToInt32 - CONVERT( INT,‘123’) - 转换 INT - 否 - ToInt64 - CONVERT( BIGINT,‘123’) - 转换 BIGINT - 否 - ToBoolean - CONVERT( BIT,‘1’) - 转换 BIT - 否 - ToChar - CONVERT( CHAR(2),'x') - 转换 CHAR - 否 
- 聚合函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Max - MAX( a.[xx] ) - 最大值 - 是 - Min - MIN( a.[xx] ) - 最小值 - 是 - Count - COUNT( a.[xx] ) - 计数 - 是 - Sum - SUM( a.[xx] ) - 合计 - 是 - Avg - AVG( a.[xx] ) - 平均 - 是 
- 数学函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Abs - ABS( a.[xx] ) - 绝对值 - 是 - Round - ROUND( a.[xx] ,2 ) - 四舍五入 - 是 
- 字符串函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - StartsWith - LIKE 'xx'+‘%’ - 左模糊 - 否 - EndsWith - LIKE ‘%’+'xx' - 右模糊 - 否 - Contains - LIKE ‘%’+'xx'+‘%’ - 全模糊 - 否 - SubString - SUBSTRING( 'xxxxxx' ,1,3) - 截取 - 否 - Replace - REPLACE( 'xxx','x','y') - 替换 - 否 - Len - LEN( 'xxx' ) - 长度 - 是 - TrimStart - LTRIM( ' xx ' ) - 修剪起始空格 - 否 - TrimEnd - RTRIM( ' xx ' ) - 修剪末尾空格 - 否 - ToUpper - UPPER( 'xx' ) - 大写 - 否 - ToLower - LOWER( 'xx' ) - 小写 - 否 - Concat - CONCAT(a.[xx1],a.[xx2]) - 字符串拼接 - 否 - Operation - [CreateTime] >= @Now_1 - 日期、数值、字符串范围比较 - 是 
- 日期函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - DateDiff - DATEDIFF( DAY ,a.[xx],b.[xx]) - 日期相差 - 是 - AddYears - DATEADD( YEAR,a.[xx],1 ) - 添加年份 - 否 - AddMonths - DATEADD( MONTH,a.[xx],1 ) - 添加月份 - 否 - AddDays - DATEADD( DAY,a.[xx],1 ) - 添加天数 - 否 - AddHours - DATEADD( HOUR,a.[xx],1 ) - 添加时 - 否 - AddMinutes - DATEADD( MINUTE,a.[xx],1 ) - 添加分 - 否 - AddSeconds - DATEADD( SECOND,a.[xx],1 ) - 添加秒 - 否 - AddMilliseconds - DATEADD( MILLISECOND,a.[xx],1 ) - 添加毫秒 - 否 - Year - YEAR( a.[xx] ) - 获取年份 - 是 - Month - MONTH( a.[xx] ) - 获取月份 - 是 - Day - DAY( a.[xx] ) - 获取天数 - 是 
- 其它函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - NewGuid - NEWID() - 获取GUID - 否 - Equals - p.[ProductCode] = '123' - 比较 - 否 - IsNull - ISNULL(a.[xx],0) - 是否为空 - 是 - Case - CASE - case - 是 - When - WHEN - when - 是 - Then - THEN - then - 是 - Else - ELSE - else - 是 - End - END - end - 是 
 
- MySql - 类型转换 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - ToString - CAST( a.`xx` AS CHAR(510) ) - 转换 CHAR(510) - 否 - ToDateTime - CAST( a.`xx` AS DATETIME ) - 转换 DATETIME - 否 - ToDecimal - CAST( a.`xx` AS DECIMAL(10,6) ) - 转换 DECIMAL(10,6) - 否 - ToDouble - CAST( a.`xx` AS DECIMAL(10,6) ) - 转换 DECIMAL(10,6) - 否 - ToInt32 - CAST( a.`xx` AS DECIMAL(10) ) - 转换 DECIMAL(10) - 否 - ToInt64 - CAST( a.`xx` AS DECIMAL(19) ) - 转换 DECIMAL(19) - 否 - ToBoolean - CAST( a.`xx` AS UNSIGNED ) - 转换 UNSIGNED - 否 - ToChar - CAST( a.`xx` AS CHAR(2) ) - 转换 CHAR(2) - 否 
- 聚合函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Max - MAX( a.`xx` ) - 最大值 - 是 - Min - MIN( a.`xx` ) - 最小值 - 是 - Count - COUNT( a.`xx` ) - 计数 - 是 - Sum - SUM( a.`xx` ) - 合计 - 是 - Avg - AVG( a.`xx` ) - 平均 - 是 
- 数学函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Abs - ABS( a.`xx` ) - 绝对值 - 是 - Round - ROUND( a.`xx` ,2 ) - 四舍五入 - 是 
- 字符串函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - StartsWith - LIKE CONCAT( 'xx','%' ) - 左模糊 - 否 - EndsWith - LIKE CONCAT( '%','xx' ) - 右模糊 - 否 - Contains - LIKE CONCAT( '%','xx','%' ) - 全模糊 - 否 - SubString - SUBSTRING( 'xxxxxx' ,1,3 ) - 截取 - 否 - Replace - REPLACE( 'xxx','x','y' ) - 替换 - 否 - Len - LEN( 'xxx' ) - 长度 - 是 - Trim - TRIM( ' xx ' ) - 修剪空格 - 否 - TrimStart - LTRIM( ' xx ' ) - 修剪起始空格 - 否 - TrimEnd - RTRIM( ' xx ' ) - 修剪末尾空格 - 否 - ToUpper - UPPER( 'xx' ) - 大写 - 否 - ToLower - LOWER( 'xx' ) - 小写 - 否 - Concat - CONCAT(a.`xx1`,a.`xx2`) - 字符串拼接 - 否 - Operation - `CreateTime` >= @Now_1 - 日期、数值、字符串范围比较 - 是 
- 日期函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - DateDiff - DATEDIFF( a.`xx`,b.`xx` ) - 日期相差 返回相差天数 - 是 - TimestampDiff - TIMESTAMPDIFF( DAY,a.`xx`,b.`xx` ) - 日期相差 指定时间单位 - 是 - AddYears - DATE_ADD( a.`xx`,INTERVAL 1 YEAR ) - 添加年份 - 否 - AddMonths - DATE_ADD( a.`xx`,INTERVAL 1 MONTH ) - 添加月份 - 否 - AddDays - DATE_ADD( a.`xx`,INTERVAL 1 DAY ) - 添加天数 - 否 - AddHours - DATE_ADD( a.`xx`,INTERVAL 1 HOUR ) - 添加时 - 否 - AddMinutes - DATE_ADD( a.`xx`,INTERVAL 1 MINUTE ) - 添加分 - 否 - AddSeconds - DATE_ADD( a.`xx`,INTERVAL 1 SECOND ) - 添加秒 - 否 - AddMilliseconds - DATE_ADD( a.`xx`,INTERVAL 1 MINUTE_SECOND ) - 添加毫秒 - 否 - Year - YEAR( a.`xx` ) - 获取年份 - 是 - Month - MONTH( a.`xx` ) - 获取月份 - 是 - Day - DAY( a.`xx` ) - 获取天数 - 是 
- 其它函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - NewGuid - UUID() - 获取GUID - 否 - Equals - p.`ProductCode` = '123' - 比较 - 否 - IfNull - IFNULL( a.`xx`,0 ) - 如果为空 - 是 - Case - CASE - case - 是 - When - WHEN - when - 是 - Then - THEN - then - 是 - Else - ELSE - else - 是 - End - END - end - 是 
 
- Oracle - 类型转换 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - ToString - CAST( a."xx" AS VARCHAR(255) ) - 转换 VARCHAR - 否 - ToDateTime - TO_TIMESTAMP( a."xx" ,'yyyy-MM-dd hh:mi:ss.ff') - 转换 DATETIME - 否 - ToDecimal - CAST( a."xx" AS DECIMAL(10,6) ) - 转换 DECIMAL - 否 - ToDouble - CAST( a."xx" AS NUMBER ) - 转换 NUMBER - 否 - ToSingle - CAST( a."xx" AS FLOAT ) - 转换 FLOAT - 否 - ToInt32 - CAST( a."xx" AS INT ) - 转换 INT - 否 - ToInt64 - CAST( a."xx" AS NUMBER ) - 转换 NUMBER - 否 - ToBoolean - CAST( a."xx" AS CHAR(1) ) - 转换 CHAR - 否 - ToChar - CAST( a."xx" AS CHAR(2) ) - 转换 CHAR - 否 
- 聚合函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Max - MAX( a."xx" ) - 最大值 - 是 - Min - MIN( a."xx" ) - 最小值 - 是 - Count - COUNT( a."xx" ) - 计数 - 是 - Sum - SUM( a."xx" ) - 合计 - 是 - Avg - AVG( a."xx" ) - 平均 - 是 
- 数学函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Abs - ABS( a."xx" ) - 绝对值 - 是 - Round - ROUND( a."xx" ,2 ) - 四舍五入 - 是 
- 字符串函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - StartsWith - LIKE CONCAT( 'xx','%' ) - 左模糊 - 否 - EndsWith - LIKE CONCAT( '%','xx' ) - 右模糊 - 否 - Contains - LIKE CONCAT( '%','xx','%' ) - 全模糊 - 否 - SubString - SUBSTRING( 'xxxxxx' ,1,3) - 截取 - 否 - Replace - REPLACE( 'xxx','x','y') - 替换 - 否 - Length - LENGTH( 'xxx' ) - 长度 - 是 - TrimStart - LTRIM( ' xx ' ) - 修剪起始空格 - 否 - TrimEnd - RTRIM( ' xx ' ) - 修剪末尾空格 - 否 - ToUpper - UPPER( 'xx' ) - 大写 - 否 - ToLower - LOWER( 'xx' ) - 小写 - 否 - Concat - CONCAT(a."xx1",a."xx2") - 字符串拼接 - 否 - Operation - ”CreateTime“ >= @Now_1 - 日期、数值、字符串范围比较 - 是 
- 日期函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Year - EXTRACT( YEAR FROM a."xx" ) - 获取年份 - 是 - Month - EXTRACT( MONTH FROM a."xx" ) - 获取月份 - 是 - Day - EXTRACT( DAY FROM a."xx" ) - 获取天数 - 是 
- 其它函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Equals - p."ProductCode" = '123' - 比较 - 否 - Nvl - NVL( a."xx",0 ) - 空,默认 - 是 - Case - CASE - case - 是 - When - WHEN - when - 是 - Then - THEN - then - 是 - Else - ELSE - else - 是 - End - END - end - 是 
 
- PostgreSql - 类型转换 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - ToString - a."xx"::VARCHAR(255) - 转换 VARCHAR - 否 - ToDateTime - a."xx"::TIMESTAMP - 转换 TIMESTAMP - 否 - ToDecimal - a."xx"::DECIMAL(10,6) - 转换 DECIMAL - 否 - ToDouble - a."xx"::NUMERIC(10,6) - 转换 NUMERIC - 否 - ToSingle - a."xx"::REAL - 转换 REAL - 否 - ToInt32 - a."xx"::INTEGER - 转换 INT - 否 - ToInt64 - a."xx"::BIGINT - 转换 BIGINT - 否 - ToBoolean - a."xx"::BOOLEAN - 转换 BOOLEAN - 否 - ToChar - a."xx"::CHAR(2) - 转换 CHAR - 否 
- 聚合函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Max - MAX( a."xx" ) - 最大值 - 是 - Min - MIN( a."xx" ) - 最小值 - 是 - Count - COUNT( a."xx" ) - 计数 - 是 - Sum - SUM( a."xx" ) - 合计 - 是 - Avg - AVG( a."xx" ) - 平均 - 是 
- 数学函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Abs - ABS( a."xx" ) - 绝对值 - 是 - Round - ROUND( a."xx" ,2 ) - 四舍五入 - 是 
- 字符串函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - StartsWith - LIKE CONCAT( '%','xx' ) - 左模糊 - 否 - EndsWith - LIKE CONCAT( 'xx','%' ) - 右模糊 - 否 - Contains - LIKE CONCAT( '%','xx','%' ) - 全模糊 - 否 - SubString - SUBSTRING( 'xxxxxx' ,1,3 ) - 截取 - 否 - Replace - REPLACE( 'xxx','x','y' ) - 替换 - 否 - Length - LENGTH( 'xxx' ) - 长度 - 是 - Trim - TRIM( ' xx ' ) - 修剪空格 - 否 - TrimStart - LTRIM( ' xx ' ) - 修剪起始空格 - 否 - TrimEnd - RTRIM( ' xx ' ) - 修剪末尾空格 - 否 - ToUpper - UPPER( 'xx' ) - 大写 - 否 - ToLower - LOWER( 'xx' ) - 小写 - 否 - Concat - CONCAT(a."xx1",a."xx2") - 字符串拼接 - 否 - Operation - ”CreateTime“ >= @Now_1 - 日期、数值、字符串范围比较 - 是 
- 日期函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - AddYears - a."xx" + INTERVAL '1 YEAR' - 添加年份 - 否 - AddMonths - a."xx" + INTERVAL '1 MONTH' - 添加月份 - 否 - AddDays - a."xx" + INTERVAL '1 DAY' - 添加天数 - 否 - AddHours - a."xx" + INTERVAL '1 HOUR' - 添加时 - 否 - AddMinutes - a."xx" + INTERVAL '1 MINUTE' - 添加分 - 否 - AddSeconds - a."xx" + INTERVAL '1 SECOND' - 添加秒 - 否 - AddMilliseconds - a."xx" + INTERVAL '1 MINUTE_SECOND' - 添加毫秒 - 否 - Year - YEAR( a."xx" ) - 获取年份 - 是 - Month - MONTH( a."xx" ) - 获取月份 - 是 - Day - DAY( a."xx" ) - 获取天数 - 是 
- 查询函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - In - IN ( a."xx" ,'x1','x2','x3' ) - In查询 - 是 - NotIn - NOT IN ( a."xx" ,'x1','x2','x3' ) - Not In查询 - 是 
- 其它函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Equals - p.”ProductCode“ = '123' - 比较 - 否 - Case - CASE - case - 是 - When - WHEN - when - 是 - Then - THEN - then - 是 - Else - ELSE - else - 是 - End - END - end - 是 
 
- Sqlite - 类型转换 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - ToString - CAST(a.[xx] AS TEXT ) - 转换 TEXT - 否 - ToDateTime - DATETIME( a.[xx] ) - 转换 DateTime - 否 - ToDecimal - CAST(a.[xx] AS DECIMAL(10,6) ) - 转换 DECIMAL - 否 - ToDouble - CAST(a.[xx] AS NUMERIC(10,6) ) - 转换 NUMERIC - 否 - ToSingle - CAST(a.[xx] AS FLOAT ) - 转换 FLOAT - 否 - ToInt32 - CAST(a.[xx] AS INTEGER ) - 转换 INTEGER - 否 - ToInt64 - CAST(a.[xx] AS BIGINT ) - 转换 BIGINT - 否 - ToBoolean - CAST(a.[xx] AS CHAR(1) ) - 转换 CHAR - 否 - ToChar - CAST(a.[xx] AS CHAR(2) ) - 转换 CHAR - 否 
- 聚合函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Max - MAX( a.[xx] ) - 最大值 - 是 - Min - MIN( a.[xx] ) - 最小值 - 是 - Count - COUNT( a.[xx] ) - 计数 - 是 - Sum - SUM( a.[xx] ) - 合计 - 是 - Avg - AVG( a.[xx] ) - 平均 - 是 
- 数学函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Abs - ABS( a.[xx] ) - 绝对值 - 是 - Round - ROUND( a.[xx] ,2 ) - 四舍五入 - 是 
- 字符串函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - StartsWith - LIKE 'xx'||'%' - 左模糊 - 否 - EndsWith - LIKE '%'||'xx' - 否 - Contains - LIKE '%'||'xx'||'%' - 全模糊 - 否 - SubString - SUBSTRING( 'xxxxxx' ,1,3 ) - 截取 - 否 - Replace - REPLACE( 'xxx','x','y' ) - 替换 - 否 - Length - LENGTH( 'xxx' ) - 长度 - 是 - Trim - TRIM( ' xx ' ) - 修剪空格 - 否 - TrimStart - LTRIM( ' xx ' ) - 修剪起始空格 - 否 - TrimEnd - RTRIM( ' xx ' ) - 修剪末尾空格 - 否 - ToUpper - UPPER( 'xx' ) - 大写 - 否 - ToLower - LOWER( 'xx' ) - 小写 - 否 - Operation - [CreateTime] >= @Now_1 - 日期、数值、字符串范围比较 - 是 
- 日期函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - AddYears - DATETIME( a.[xx],'1 YEAR' ) - 添加年份 - 否 - AddMonths - DATETIME( a.[xx],'1 MONTH' ) - 添加月份 - 否 - AddDays - DATETIME( a.[xx],'1 DAY' ) - 添加天数 - 否 - AddHours - DATETIME( a.[xx],'1 HOUR' ) - 添加时 - 否 - AddMinutes - DATETIME( a.[xx],'1 MINUTE' ) - 添加分 - 否 - AddSeconds - DATETIME( a.[xx],'1 SECOND' ) - 添加秒 - 否 - AddMilliseconds - DATETIME( a.[xx],'1 YEAR' ) - 添加毫秒 - 否 - Year - STRFTIME( '%Y', a.[xx] ) - 获取年份 - 是 - Month - STRFTIME( '%m', a.[xx] ) - 获取月份 - 是 - Day - STRFTIME( '%j', a.[xx] ) - 获取天数 - 是 
- 其它函数 - 方法名称 - 解析示例值 - 说明 - 自定义函数 - Equals - p.”ProductCode“ = '123' - 比较 - 否 - Case - CASE - case - 是 - When - WHEN - when - 是 - Then - THEN - then - 是 - Else - ELSE - else - 是 - End - END - end - 是 
 
 
- 添加自定义函数解析 - //注意:只能扩展未实现的方法名称 不能覆盖原有的实现 Models.DbType.MySQL.AddSqlFunc("方法名称", (visit, method, sqlStack) => { //解析逻辑 });
九、数据库日志
				        db.Aop.DbLog = (sql, dp) =>
                {
                    Console.WriteLine($"执行Sql:{sql}");                    if (dp != null)
                    {
                        foreach (var item in dp)
                        {
                            Console.WriteLine($"参数名称:{item.ParameterName} 参数值:{item.ParameterValue}");
                        }
                    }
                };十、事务
- 普通事务 - try { db.Ado.BeginTran();//开启事务 // 执行 CRUD db.Ado.CommitTran();//提交事务 } catch (Exception ex) { Console.WriteLine(ex.Message); db.Ado.RollbackTran();//回滚事务 }
- 更大范围的事务 - try { db.BeginTran();//开启事务 // 执行 CRUD db.CommitTran();//提交事务 } catch (Exception ex) { db.RollbackTran();//回滚事务 Console.WriteLine(ex.Message); }
十一、多租户
- 改变数据库 - //数据库配置可从Json配置文件加载 IDbContext db = new DbContext(new List<DbOptions>() { new DbOptions() { DbId = "1", DbType = Models.DbType.SQLServer, ProviderName = "System.Data.SqlClient", FactoryName = "System.Data.SqlClient.SqlClientFactory,System.Data", ConnectionStrings = "server=localhost;database=Test;user=sa;pwd=123456789;min pool size=0;max pool size=100;connect timeout=120;" }, new DbOptions() { DbId = "2", DbType = Models.DbType.MySQL, ProviderName = "MySqlConnector", FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector", ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=0;max pool size=100;connect timeout=120;" }}); db.ChangeDb("2");//切换到MySQL
十二、原生特性支持
    /// <summary>
    /// 产品
    /// </summary>
    [Table("ProductMain")]
    public class Product
    {
        /// <summary>
        /// 产品ID
        /// </summary>
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ProductId { get; set; }        /// <summary>
        /// 产品编号
        /// </summary>
        [Column("ProductCode")]//不标记默认取当前属性名称
        public string ProductCode { get; set; }        /// <summary>
        /// 自定义1
        /// </summary>
        [NotMapped]
        public string Custom1 { get; set; }        
        /// <summary>
        /// 自定义2
        /// </summary>
        [Column(TypeName="Json")]//类型标记为Json格式对象 匿名对象属性以及字典值类型 IsClass&&!type.Equals(typeof(string)) 将自动序列化成Json格式
        public Category Custom2 { get; set; }
    }十三、原生Ado
                // 原始起步
                // var conn = db.Ado.DbProviderFactory.CreateConnection();
                // var cmd = conn.CreateCommand();
                // 封装的方法分别以Execute和Create开头以及预处理 PrepareCommand 方法
                // 该方法可以自动帮你处理执行的预操作,主要作用是代码复用。
                // 当有非常复杂的查询 ORM不能满足需求的时候可以使用原生Ado满足业务需求
                // 构建数据集核心扩展方法 分别有 FirstBuild ListBuild DictionaryBuild DictionaryListBuild
                var data = db.Ado.ExecuteReader(CommandType.Text, "select * from product", null).ListBuild<Product>();十四、工作单元
- 注册数据库上下文和工作单元服务 - var builder = WebApplication.CreateBuilder(args); var configuration = builder.Configuration;// 添加数据库上下文服务builder.Services.AddFastDbContext();// 添加工作单元服务builder.Services.AddUnitOfWork();// 加载数据库配置builder.Services.Configure<List<DbOptions>>(configuration.GetSection("DbConfig"));
- 实际应用 - /// <summary> /// 工作单元 /// </summary> private readonly IUnitOfWork unitOfWork; /// <summary> /// 构造方法 /// </summary> /// <param name="unitOfWork">工作单元</param> public UnitOfWorkTestService(IUnitOfWork unitOfWork) { this.unitOfWork = unitOfWork; } /// <summary> /// 测试 /// </summary> /// <returns></returns> public string Test() { //unitOfWork 对象无需显示使用using var result1 = unitOfWork.Db.Insert(new Category() { CategoryName = "类别3" }).Exceute(); var result2 = unitOfWork.Db.Insert(new Product() { ProductCode = "测试工作单元", }).Exceute(); unitOfWork.Commit(); return "工作单元执行完成..."; }
十五、大数据导入
- 批复制 仅支持SqlServer Oracle MySql PostgreSql - var list = new List<Product>(); for (int j = 1; j <= 100000; j++) { list.Add(new Product() { CategoryId = 1, ProductCode = $"测试编号_{Timestamp.CurrentTimestampSeconds()}_{j}", ProductName = $"测试名称_{Timestamp.CurrentTimestampSeconds()}_{j}", CreateTime = DateTime.Now, Custom1 = $"测试自定义1_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom2 = $"测试自定义2_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom3 = $"测试自定义3_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom4 = $"测试自定义4_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom5 = $"测试自定义5_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom6 = $"测试自定义6_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom7 = $"测试自定义7_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom8 = $"测试自定义8_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom9 = $"测试自定义9_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom10 = $"测试自定义10_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom11 = $"测试自定义11_{Timestamp.CurrentTimestampSeconds()}_{j}", Custom12 = $"测试自定义12_{Timestamp.CurrentTimestampSeconds()}_{j}", }); } db.Fast<Product>().BulkCopy(list);