沙雕小溪 发表于 2023-4-22 17:51:49

一个可用于生产项目 基于 .NET 6 自研ORM

Fast Framework

作者 Mr-zhong
代码改变世界....
一、前言

Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer Oracle MySql PostgreSql Sqlite
优点: 体积小、可动态切换不同实现类库、原生支持微软特性、流畅API、使用简单、性能高、模型数据绑定采用 委托、强大的表达式解析、支持多种子查询可实现较为复杂查询、源代码可读性强。
缺点:目前仅支持Db Frist   Code Frist 后续迭代。
开源地址 https://github.com/China-Mr-zhong/Fast.Framework (唯一)
目前作者已使用该框架应用多个生产项目
个别亮点功能:数值类型绑定自动格式化小数点后面多余的0、表达式参数名称自动编排 无需强制统一参数名称
本作者不提供任何性能对比数据,请各位感兴趣的自行测试,对比前建议预热连接
二、项目明细

名称说明Fast.Framework框架主项目Fast.Framework.Logging基于微软接口实现的文件日志(非必要可不引用)Fast.Framework.Test控制台测试项目Fast.Framework.UnitTest单元测试项目Fast.Framework.Web.TestWeb测试项目三、核心对象


[*]Ado 原生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;"
                }});
[*]DbOptionsJson文件配置格式
"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;"
    }]
[*]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();
            Console.WriteLine($"实体对象插入 受影响行数 {result}");
[*]实体对象插入并返回自增ID 仅支持 SQLServer MySQL SQLite
            var product = new Product()
            {
                ProductCode = "1001",
                ProductName = "测试产品1"
            };
            var result = db.Insert(product).ExceuteReturnIdentity();
            Console.WriteLine($"实体对象插入 返回自增ID {result}");
[*]实体对象列表插入
            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();
            Console.WriteLine($"实体对象列表插入 受影响行数 {result}");
[*]匿名对象插入
            var obj = new
            {
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:需要使用As方法显示指定表名称
            var result = db.Insert(obj).As("Product").Exceute();
            Console.WriteLine($"匿名对象插入 受影响行数 {result}");
[*]匿名对象列表插入
            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();
            Console.WriteLine($"匿名对象列表插入 受影响行数 {result}");
[*]字典插入
            var product = new Dictionary<string, object>()
            {
                {"ProductCode","1001"},
                { "ProductName","测试商品1"}
            };
            var result = db.Insert(product).As("Product").Exceute();
            Console.WriteLine($"字典插入 受影响行数 {result}");
[*]字典列表插入
            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();
            Console.WriteLine($"字典列表插入 受影响行数 {result}");
五、删除


[*]实体对象删除
            var product = new Product()
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:必须标记KeyAuttribute特性 否则将抛出异常
            var result = db.Delete(product).Exceute();
            Console.WriteLine($"实体删除 受影响行数 {result}");
[*]无条件删除
            var result = db.Delete<Product>().Exceute();
            Console.WriteLine($"无条件删除 受影响行数 {result}");
[*]表达式删除
            var result = await db.Delete<Product>().Where(w => w.ProductId == 1).ExceuteAsync();
            Console.WriteLine($"条件删除 受影响行数 {result}");
[*]特殊删除
                              //特殊用法 如需单个条件或多个可搭配 WhereColumn或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();
            Console.WriteLine($"对象更新 受影响行数 {result}");
[*]指定列更新
            var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).Columns("ProductCode", "ProductName").Exceute();
                                                // 字段很多的话可以直接new List<string>(){"列1","列2"}
[*]忽略列更新
            var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).IgnoreColumns("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();
            Console.WriteLine($"对象列表更新 受影响行数 {result}");
[*]匿名对象更新
            var obj = new
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:需要显示指定表名称 以及更新条件 使用 Where或者WhereColumns方法均可
            var result = db.Update(obj).As("product").WhereColumns("ProductId").Exceute();
            Console.WriteLine($"匿名对象更新 受影响行数 {result}");
[*]匿名对象列表更新
            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();
            Console.WriteLine($"匿名对象列表更新 受影响行数 {result}");
[*]字典更新
            var product = new Dictionary<string, object>()
            {
                { "ProductId",1},
                {"ProductCode","1001"},
                { "ProductName","测试商品1"}
            };
            var result = db.Update(product).As("Product").WhereColumns("ProductId").Exceute();
            Console.WriteLine($"字典更新 受影响行数 {result}");
[*]字典列表更新
            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();
            Console.WriteLine($"字典列表更新 受影响行数 {result}");
[*]指定条件更新
            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();

//由于没有专门去扩展 Not Like 方法,可以用取反或使用比较变通实现 例如 w.ProductName.StartsWith("左模糊")==false
//Mysql举例 最终解析后的结果为 `ProductName` Like '%左模糊' = 0 这种用法数据库是支持的 相当于 Not Like
[*]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方法
[*]查询并插入仅支持同实例的数据库 跨库 个人还是建议 用事务分开写查询和插入
                //方式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 需要注意的是 显示指定不带 列标识符 例如 `列名称1` 如有字段冲突 可自行加上标识符
                var result2 = db.Query<Product>().Where(w => w.ProductId == 1489087).Select(s => new
                {
                  s.ProductCode,
                  s.ProductName
                }).Insert("表名称 同实例不同库 可以使用 db.数据库名称.表名称 ", "列名称1", "列名称2", "`带标识的列名称3`");

                //方式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查询
                // 方式1
                var data1 = db.Query<Product>().Where(w => SqlFunc.In(w.ProductCode, "1001", "1002")).ToList();

                // 方式2
                var data2 = db.Query<Product>().Where(w => SqlFunc.In(w.ProductCode, new List<string>() { "123", "456" })).ToList();

                // 方式3 需要动态更新IN值 使用这种
                var list = new List<string>() { "123", "456" };
                var data3 = db.Query<Product>().Where(w => SqlFunc.In(w.ProductCode, list)).ToList();

                // 方法4 参数同上一样 单独分离IN和NotIN 是为了兼容匿名查询
                var data4 = db.Query<Product>().In("字段名称", "1001", "1002").ToList();
[*]Select子查询
                var subQuery = db.Query<Product>().Where(w => w.ProductId == 1).Select(s => s.ProductName);
                var sql1 = db.Query<Product>().Select(s => new Product()
                {
                  Custom1 = db.SubQuery<string>(subQuery)// SubQuery 的泛型是根据你左边赋值的属性类型来定义
                }).ToList();
                // 这种没有使用new 的 泛型可随意定义 实际作用就是避免 对象属性赋值类型冲突的问题
                var sql2 = db.Query<Product>().Select(s => db.SubQuery<string>(subQuery)).ToList();
[*]From子查询
                var subQuery = db.Query<Product>();
                var data = db.Query(subQuery).OrderBy(o => o.ProductCode).ToList();
[*]Join子查询
                var subQuery = db.Query<Product>();
                var data = db.Query<Product>().InnerJoin(subQuery, (a, b) => a.ProductId == b.ProductId).ToList();
[*]Include查询
                // 联表条件 默认优先匹配主键 其次带有ID结尾的名称
                var data = db.Query<Category>().Include(i => i.Products).ToList();
八、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

[*]SqlServer

[*]类型转换
方法名称解析示例值说明自定义函数ToStringCONVERT( VARCHAR(255),123)转换 VARCHAR否ToDateTimeCONVERT( DATETIME,‘2022-09-16’)转换 DATETIME否ToDecimalCONVERT( DECIMAL(10,6),‘123’)转换 DECIMAL否ToDoubleCONVERT( NUMERIC(10,6),‘123’)转换 NUMERIC否ToSingleCONVERT( FLOAT,‘123’)转换 FLOAT否ToInt32CONVERT( INT,‘123’)转换 INT否ToInt64CONVERT( BIGINT,‘123’)转换 BIGINT否ToBooleanCONVERT( BIT,‘1’)转换 BIT否ToCharCONVERT( CHAR(2),'x')转换 CHAR否
[*]聚合函数
方法名称解析示例值说明自定义函数MaxMAX( a. )最大值是MinMIN( a. )最小值是CountCOUNT( a. )计数是SumSUM( a. )合计是AvgAVG( a. )平均是
[*]数学函数
方法名称解析示例值说明自定义函数AbsABS( a. )绝对值是RoundROUND( a. ,2 )四舍五入是
[*]字符串函数
方法名称解析示例值说明自定义函数StartsWithLIKE ‘%’+'xx'左模糊否EndsWithLIKE 'xx'+‘%’右模糊否ContainsLIKE ‘%’+'xx'+‘%’全模糊否SubStringSUBSTRING( 'xxxxxx' ,1,3)截取否ReplaceREPLACE( 'xxx','x','y')替换否LenLEN( 'xxx' )长度是TrimStartLTRIM( ' xx ' )修剪起始空格否TrimEndRTRIM( ' xx ' )修剪末尾空格否ToUpperUPPER( 'xx' )大写否ToLowerLOWER( 'xx' )小写否OperationCreateTime >= @Now_1日期、数值、字符串范围比较是
[*]日期函数
方法名称解析示例值说明自定义函数DateDiffDATEDIFF( DAY ,a.,b.)日期相差是AddYearsDATEADD( YEAR,a.,1 )添加年份否AddMonthsDATEADD( MONTH,a.,1 )添加月份否AddDaysDATEADD( DAY,a.,1 )添加天数否AddHoursDATEADD( HOUR,a.,1 )添加时否AddMinutesDATEADD( MINUTE,a.,1 )添加分否AddSecondsDATEADD( SECOND,a.,1 )添加秒否AddMillisecondsDATEADD( MILLISECOND,a.,1 )添加毫秒否YearYEAR( a. )获取年份是MonthMONTH( a. )获取月份是DayDAY( a. )获取天数是
[*]查询函数
方法名称解析示例值说明自定义函数InIN( a. ,'x1','x2','x3')In查询是NotInNOT IN( a. ,'x1','x2','x3')Not In查询是
[*]其它函数
方法名称解析示例值说明自定义函数NewGuidNEWID()获取GUID否Equalsp. = '123'比较否IsNullISNULL(a.,0)是否为空是CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是

[*]MySql

[*]类型转换
方法名称解析示例值说明自定义函数ToStringCAST( a.`xx` AS CHAR(510) )转换 CHAR(510)否ToDateTimeCAST( a.`xx` AS DATETIME )转换 DATETIME否ToDecimalCAST( a.`xx` AS DECIMAL(10,6) )转换 DECIMAL(10,6)否ToDoubleCAST( a.`xx` AS DECIMAL(10,6) )转换 DECIMAL(10,6)否ToInt32CAST( a.`xx` AS DECIMAL(10) )转换 DECIMAL(10)否ToInt64CAST( a.`xx` AS DECIMAL(19) )转换 DECIMAL(19)否ToBooleanCAST( a.`xx`AS UNSIGNED )转换 UNSIGNED否ToCharCAST( a.`xx` AS CHAR(2) )转换 CHAR(2)否
[*]聚合函数
方法名称解析示例值说明自定义函数MaxMAX( a.`xx` )最大值是MinMIN( a.`xx` )最小值是CountCOUNT( a.`xx` )计数是SumSUM( a.`xx` )合计是AvgAVG( a.`xx` )平均是
[*]数学函数
方法名称解析示例值说明自定义函数AbsABS( a.`xx` )绝对值是RoundROUND( a.`xx` ,2 )四舍五入是
[*]字符串函数
方法名称解析示例值说明自定义函数StartsWithLIKE CONCAT( '%','xx' )左模糊否EndsWithLIKE CONCAT( xx','%' )右模糊否ContainsLIKE CONCAT( '%','xx','%' )全模糊否SubStringSUBSTRING('xxxxxx' ,1,3 )截取否ReplaceREPLACE( 'xxx','x','y' )替换否LenLEN( 'xxx' )长度是TrimTRIM( ' xx ' )修剪空格否TrimStartLTRIM( ' xx ' )修剪起始空格否TrimEndRTRIM( ' xx ' )修剪末尾空格否ToUpperUPPER( 'xx' )大写否ToLowerLOWER( 'xx' )小写否ConcatCONCAT(a.`xx1`,a.`xx2`)字符串拼接是
[*]日期函数
方法名称解析示例值说明自定义函数DateDiffDATEDIFF( a.`xx`,b.`xx` )日期相差 返回相差天数是TimestampDiffTIMESTAMPDIFF( DAY,a.`xx`,b.`xx` )日期相差 指定时间单位是AddYearsDATE_ADD( a.`xx`,INTERVAL 1 YEAR )添加年份否AddMonthsDATE_ADD( a.`xx`,INTERVAL 1 MONTH )添加月份否AddDaysDATE_ADD( a.`xx`,INTERVAL 1 DAY )添加天数否AddHoursDATE_ADD( a.`xx`,INTERVAL 1 HOUR )添加时否AddMinutesDATE_ADD( a.`xx`,INTERVAL 1 MINUTE )添加分否AddSecondsDATE_ADD( a.`xx`,INTERVAL 1 SECOND )添加秒否AddMillisecondsDATE_ADD( a.`xx`,INTERVAL 1 MINUTE_SECOND )添加毫秒否YearYEAR( a.`xx` )获取年份是MonthMONTH( a.`xx` )获取月份是DayDAY( a.`xx` )获取天数是
[*]查询函数
方法名称解析示例值说明自定义函数InIN( a.`xx` ,'x1','x2','x3' )In查询是NotInNOT IN( a.`xx` ,'x1','x2','x3' )Not In查询是
[*]其它函数
方法名称解析示例值说明自定义函数NewGuidUUID()获取GUID否Equalsp.`ProductCode` = '123'比较否IfNullIFNULL( a.`xx`,0 )如果为空是CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是

[*]Oracle

[*]类型转换
方法名称解析示例值说明自定义函数ToStringCAST( a."xx" AS VARCHAR(255) )转换 VARCHAR否ToDateTimeTO_TIMESTAMP( a."xx" ,'yyyy-MM-dd hh:mi:ss.ff')转换 DATETIME否ToDecimalCAST( a."xx" AS DECIMAL(10,6) )转换 DECIMAL否ToDoubleCAST( a."xx" AS NUMBER )转换 NUMBER否ToSingleCAST( a."xx" AS FLOAT )转换 FLOAT否ToInt32CAST( a."xx" AS INT )转换 INT否ToInt64CAST( a."xx" AS NUMBER )转换 NUMBER否ToBooleanCAST( a."xx" AS CHAR(1) )转换 CHAR否ToCharCAST( a."xx" AS CHAR(2) )转换 CHAR否
[*]聚合函数
方法名称解析示例值说明自定义函数MaxMAX( a."xx" )最大值是MinMIN( a."xx" )最小值是CountCOUNT( a."xx" )计数是SumSUM( a."xx" )合计是AvgAVG( a."xx" )平均是
[*]数学函数
方法名称解析示例值说明自定义函数AbsABS( a."xx" )绝对值是RoundROUND( a."xx" ,2 )四舍五入是
[*]字符串函数
方法名称解析示例值说明自定义函数StartsWithLIKE CONCAT( '%','xx' )左模糊否EndsWithLIKE CONCAT( 'xx','%' )右模糊否ContainsLIKE CONCAT( '%','xx','%' )全模糊否SubStringSUBSTRING( 'xxxxxx' ,1,3)截取否ReplaceREPLACE( 'xxx','x','y')替换否LengthLENGTH( 'xxx' )长度是TrimStartLTRIM( ' xx ' )修剪起始空格否TrimEndRTRIM( ' xx ' )修剪末尾空格否ToUpperUPPER( 'xx' )大写否ToLowerLOWER( 'xx' )小写否ConcatCONCAT(a."xx1",a."xx2")字符串拼接是
[*]日期函数
方法名称解析示例值说明自定义函数YearEXTRACT( YEAR FROM a."xx" )获取年份是MonthEXTRACT( MONTH FROM a."xx" )获取月份是DayEXTRACT( DAY FROM a."xx" )获取天数是
[*]查询函数
方法名称解析示例值说明自定义函数InIN( a."xx" ,'x1','x2','x3')In查询是NotInNOT IN( a."xx",'x1','x2','x3')Not In查询是
[*]其它函数
方法名称解析示例值说明自定义函数Equalsp."ProductCode" = '123'比较否NvlNVL( a."xx",0 )空,默认是CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是

[*]PostgreSql

[*]类型转换
方法名称解析示例值说明自定义函数ToStringa."xx"::VARCHAR(255)转换 VARCHAR否ToDateTimea."xx"::TIMESTAMP转换 TIMESTAMP否ToDecimala."xx"::DECIMAL(10,6)转换 DECIMAL否ToDoublea."xx"::NUMERIC(10,6)转换 NUMERIC否ToSinglea."xx"::REAL转换 REAL否ToInt32a."xx"::INTEGER转换 INT否ToInt64a."xx"::BIGINT转换 BIGINT否ToBooleana."xx"::BOOLEAN转换 BOOLEAN否ToChara."xx"::CHAR(2)转换 CHAR否
[*]聚合函数
方法名称解析示例值说明自定义函数MaxMAX( a."xx" )最大值是MinMIN( a."xx" )最小值是CountCOUNT( a."xx" )计数是SumSUM( a."xx" )合计是AvgAVG( a."xx" )平均是
[*]数学函数
方法名称解析示例值说明自定义函数AbsABS( a."xx" )绝对值是RoundROUND( a."xx" ,2 )四舍五入是
[*]字符串函数
方法名称解析示例值说明自定义函数StartsWithLIKE CONCAT( '%','xx' )左模糊否EndsWithLIKE CONCAT( 'xx','%' )右模糊否ContainsLIKE CONCAT( '%','xx','%' )全模糊否SubStringSUBSTRING('xxxxxx' ,1,3 )截取否ReplaceREPLACE( 'xxx','x','y' )替换否LengthLENGTH( 'xxx' )长度是TrimTRIM( ' xx ' )修剪空格否TrimStartLTRIM( ' xx ' )修剪起始空格否TrimEndRTRIM( ' xx ' )修剪末尾空格否ToUpperUPPER( 'xx' )大写否ToLowerLOWER( 'xx' )小写否ConcatCONCAT(a."xx1",a."xx2")字符串拼接是
[*]日期函数
方法名称解析示例值说明自定义函数AddYearsa."xx" + INTERVAL '1 YEAR'添加年份否AddMonthsa."xx" + INTERVAL '1 MONTH'添加月份否AddDaysa."xx" + INTERVAL '1 DAY'添加天数否AddHoursa."xx" + INTERVAL '1 HOUR'添加时否AddMinutesa."xx" + INTERVAL '1 MINUTE'添加分否AddSecondsa."xx" + INTERVAL '1 SECOND'添加秒否AddMillisecondsa."xx" + INTERVAL '1 MINUTE_SECOND'添加毫秒否YearYEAR( a."xx" )获取年份是MonthMONTH( a."xx" )获取月份是DayDAY( a."xx" )获取天数是
[*]查询函数
方法名称解析示例值说明自定义函数InIN( a."xx" ,'x1','x2','x3' )In查询是NotInNOT IN( a."xx" ,'x1','x2','x3' )Not In查询是
[*]其它函数
方法名称解析示例值说明自定义函数Equalsp.”ProductCode“ = '123'比较否CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是

[*]Sqlite

[*]类型转换
方法名称解析示例值说明自定义函数ToStringCAST(a. AS TEXT )转换 TEXT否ToDateTimeDATETIME( a. )转换 DateTime否ToDecimalCAST(a. AS DECIMAL(10,6) )转换 DECIMAL否ToDoubleCAST(a. AS NUMERIC(10,6) )转换 NUMERIC否ToSingleCAST(a. AS FLOAT )转换 FLOAT否ToInt32CAST(a. AS INTEGER )转换 INTEGER否ToInt64CAST(a. AS BIGINT )转换 BIGINT否ToBooleanCAST(a. AS CHAR(1) )转换 CHAR否ToCharCAST(a. AS CHAR(2) )转换 CHAR否
[*]聚合函数
方法名称解析示例值说明自定义函数MaxMAX( a. )最大值是MinMIN( a. )最小值是CountCOUNT( a. )计数是SumSUM( a. )合计是AvgAVG( a. )平均是
[*]数学函数
方法名称解析示例值说明自定义函数AbsABS( a. )绝对值是RoundROUND( a. ,2 )四舍五入是
[*]字符串函数
方法名称解析示例值说明自定义函数StartsWithLIKE '%'||'xx'左模糊否EndsWithLIKE 'xx'||'%'右模糊否ContainsLIKE '%'||'xx'||'%'全模糊否SubStringSUBSTRING('xxxxxx' ,1,3 )截取否ReplaceREPLACE( 'xxx','x','y' )替换否LengthLENGTH( 'xxx' )长度是TrimTRIM( ' xx ' )修剪空格否TrimStartLTRIM( ' xx ' )修剪起始空格否TrimEndRTRIM( ' xx ' )修剪末尾空格否ToUpperUPPER( 'xx' )大写否ToLowerLOWER( 'xx' )小写否
[*]日期函数
方法名称解析示例值说明自定义函数AddYearsDATETIME( a.,'1 YEAR' )添加年份否AddMonthsDATETIME( a.,'1 MONTH' )添加月份否AddDaysDATETIME( a.,'1 DAY' )添加天数否AddHoursDATETIME( a.,'1 HOUR' )添加时否AddMinutesDATETIME( a.,'1 MINUTE' )添加分否AddSecondsDATETIME( a.,'1 SECOND' )添加秒否AddMillisecondsDATETIME( a.,'1 YEAR' )添加毫秒否YearSTRFTIME( '%Y', a. )获取年份是MonthSTRFTIME( '%m', a. )获取月份是DaySTRFTIME( '%j', a. )获取天数是
[*]查询函数
方法名称解析示例值说明自定义函数InIN( a."xx" ,'x1','x2','x3' )In查询是NotInNOT IN( a."xx" ,'x1','x2','x3' )Not In查询是
[*]其它函数
方法名称解析示例值说明自定义函数Equalsp.”ProductCode“ = '123'比较否CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是


[*]添加自定义函数解析
                //注意:只能扩展未实现的方法名称 不能覆盖原有的实现
                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>
   
    public class Product
    {
      /// <summary>
      /// 产品ID
      /// </summary>
      
      public int ProductId { get; set; }

      /// <summary>
      /// 产品编号
      /// </summary>
      //不标记默认取当前属性名称
      public string ProductCode { get; set; }

      /// <summary>
      /// 自定义1
      /// </summary>
      
      public string Custom1 { get; set; }
    }十三、原生Ado

                // 原始起步
                // var conn = db.Ado.DbProviderFactory.CreateConnection();
                // var cmd = conn.CreateCommand();

                // 封装的方法分别以Execute和Create开头以及预处理 PrepareCommand 方法
                // 该方法可以自动帮你处理执行的预操作,主要作用是代码复用。

                // 当有非常复杂的查询 ORM不能满足需求的时候可以使用原生Ado满足业务需求

                // 构建数据集核心扩展方法 分别有 FristBuild 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.AddFastUnitOfWork();

// 加载数据库配置
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 "工作单元执行完成...";
      }
十五、大数据导入

<ul>批复制 仅支持SqlServer Oracle MySql PostgreSql
                var list = new List();                for (int j = 1; j
页: [1]
查看完整版本: 一个可用于生产项目 基于 .NET 6 自研ORM