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

2023-08-29 10:18:37 浏览数 (2)

一、前言

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.Test

Web测试项目

三、核心对象

Ado 原生Ado对象

代码语言:javascript复制
                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 即可

代码语言:javascript复制
                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文件配置格式

代码语言:javascript复制
"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;"
    }]

主从分离(读写分离)配置

代码语言:javascript复制
  "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 依赖注入

代码语言:javascript复制
// 注册服务 
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;
    }
}
四、插入

实体对象插入

代码语言:javascript复制
            var product = new Product()
            {
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            var result = db.Insert(product).Exceute();
            Console.WriteLine($"实体对象插入 受影响行数 {result}");

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

代码语言:javascript复制
            var product = new Product()
            {
                ProductCode = "1001",
                ProductName = "测试产品1"
            };
            var result = db.Insert(product).ExceuteReturnIdentity();
            Console.WriteLine($"实体对象插入 返回自增ID {result}");

实体对象列表插入

代码语言:javascript复制
            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}");

匿名对象插入

代码语言:javascript复制
            var obj = new
            {
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:需要使用As方法显示指定表名称
            var result = db.Insert(obj).As("Product").Exceute();
            Console.WriteLine($"匿名对象插入 受影响行数 {result}");

匿名对象列表插入

代码语言:javascript复制
            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}");

字典插入

代码语言:javascript复制
            var product = new Dictionary<string, object>()
            {
                {"ProductCode","1001"},
                { "ProductName","测试商品1"}
            };
            var result = db.Insert(product).As("Product").Exceute();
            Console.WriteLine($"字典插入 受影响行数 {result}");

字典列表插入

代码语言:javascript复制
            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}");
五、删除

实体对象删除

代码语言:javascript复制
            var product = new Product()
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:必须标记KeyAuttribute特性 否则将抛出异常
            var result = db.Delete(product).Exceute();
            Console.WriteLine($"实体删除 受影响行数 {result}");

无条件删除

代码语言:javascript复制
            var result = db.Delete<Product>().Exceute();
            Console.WriteLine($"无条件删除 受影响行数 {result}");

表达式删除

代码语言:javascript复制
            var result = await db.Delete<Product>().Where(w => w.ProductId == 1).ExceuteAsync();
            Console.WriteLine($"条件删除 受影响行数 {result}");

特殊删除

代码语言:javascript复制
			      //特殊用法 如需单个条件或多个可搭配 WhereColumn或WhereColumns方法
            var result = await db.Delete<object>().As("Product").ExceuteAsync();
            Console.WriteLine($"无实体删除 受影响行数 {result}");
六、更新

实体对象更新

代码语言:javascript复制
            var product = new Product()
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:标记KeyAuttribute特性属性或使用Where条件,为了安全起见全表更新将必须使用Where方法
            var result = db.Update(product).Exceute();
            Console.WriteLine($"对象更新 受影响行数 {result}");

指定列更新

代码语言:javascript复制
            var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).Columns("ProductCode", "ProductName").Exceute();
						// 字段很多的话可以直接new List<string>(){"列1","列2"}

忽略列更新

代码语言:javascript复制
            var result = db.Update<Product>(new Product() { ProductCode = "1001", ProductName = "1002" }).IgnoreColumns("Custom1").Exceute();
            // 同上使用方法一样

实体对象列表更新

代码语言:javascript复制
            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}");

匿名对象更新

代码语言:javascript复制
            var obj = new
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            //注意:需要显示指定表名称 以及更新条件 使用 Where或者WhereColumns方法均可
            var result = db.Update(obj).As("product").WhereColumns("ProductId").Exceute();
            Console.WriteLine($"匿名对象更新 受影响行数 {result}");

匿名对象列表更新

代码语言:javascript复制
            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}");

字典更新

代码语言:javascript复制
            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}");

字典列表更新

代码语言:javascript复制
            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}");

指定条件更新

代码语言:javascript复制
            var product = new Product()
            {
                ProductId = 1,
                ProductCode = "1001",
                ProductName = "测试商品1"
            };
            var result = db.Update(product).Where(p => p.ProductId == 100).Exceute();
            Console.WriteLine($"表达式更新 受影响行数 {result}");

并发更新 乐观锁-版本控制

代码语言:javascript复制
                //注意:仅支持非列表更新 版本列数据类型仅支持 object、string、Guid 时间类型存在精度丢失所以不做支持
				var obj = db.Query<Product>().Where(w => w.ProductId == 1).Frist();
                obj.Custom1 = "测试版本控制修改";
				//参数为 true 更新失败将抛出异常
                var result = db.Update(obj).ExceuteWithOptLock(true);
七、查询

单一查询

代码语言:javascript复制
            var data = db.Query<Product>().First();

列表查询

代码语言:javascript复制
            var data = db.Query<Product>().ToList();

返回单个字典

代码语言:javascript复制
            var data = db.Query<Product>().ToDictionary();

返回字典列表

代码语言:javascript复制
            var data = db.Query<Product>().ToDictionaryList();

分页查询

代码语言:javascript复制
            //分页查询不返回总数
            var data = db.Query<Product>().ToPageList(1,100);
            //分页查询返回总数
			var total = 0;//定义总数变量
			var data = db.Query<Product>().ToPageList(1, 1, ref total);
            Console.WriteLine($"总数:{total}");

计数查询

代码语言:javascript复制
            var data = db.Query<Product>().Count();

任何查询

代码语言:javascript复制
            var data = db.Query<Product>().Any();

条件查询

代码语言:javascript复制
            var data = db.Query<Product>().Where(w => w.ProductId == 1).ToList;

Like 查询

代码语言:javascript复制
            var data = db.Query<Product>().Where(w => w.ProductName.StartsWith("左模糊") || w.ProductName.EndsWith("右模糊") || w.ProductName.Contains("全模糊")).ToList();

Not Like查询

代码语言:javascript复制
var data = db.Query<Product>().Where(w => !w.ProductName.StartsWith("左模糊") || !w.ProductName.EndsWith("右模糊") || !w.ProductName.Contains("全模糊")).ToList();

Select查询 (选择字段)

代码语言:javascript复制
            var data = db.Query<Product>().Select(s => new
            {
                s.ProductId,
                s.ProductName
            }).ToList();

Select查询 (Case When)

代码语言:javascript复制
                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();

分组查询

代码语言:javascript复制
            var data = db.Query<Product>().GroupBy(s => new
            {
                s.ProductId,
                s.ProductName
            }).ToList();

分组聚合查询

代码语言:javascript复制
            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();

排序查询

代码语言:javascript复制
            var data = db.Query<Product>().OrderBy(s => new
            {
                s.CreateTime
            }).ToList();
            //这是多个字段排序使用方法 还有其它重载方法

Having查询

代码语言:javascript复制
            var data = db.Query<Product>().GroupBy(s => new
            {
                s.ProductId,
                s.ProductName
            }).Having(s => SqlFunc.Count(s.ProductId) > 1).ToList();
            //必须先使用GroupBy方法 懂得都懂

联表查询

代码语言:javascript复制
            var data = db.Query<Product>().LeftJoin<Class1>((a, b) => a.ProductId == b.ProductId).ToList();
            // 右连接 RightJoin 内连接 InnerJoin 全连接 FullJoin

联合查询

代码语言:javascript复制
            var query1 = db.Query<Product>();
            var query2 = db.Query<Product>();
            db.Union(query1, query2);//联合
            db.UnionAll(query1, query2);//全联合
            //执行查询调用Toxx方法

查询并插入 仅支持同实例的数据库 跨库 个人还是建议 用事务分开写查询和插入

代码语言:javascript复制
                //方式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查询

代码语言:javascript复制
                // 方式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子查询

代码语言:javascript复制
                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子查询

代码语言:javascript复制
                var subQuery = db.Query<Product>();
                var data = db.Query(subQuery).OrderBy(o => o.ProductCode).ToList();

Join子查询

代码语言:javascript复制
                var subQuery = db.Query<Product>();
                var data = db.Query<Product>().InnerJoin(subQuery, (a, b) => a.ProductId == b.ProductId).ToList();

Include查询

代码语言:javascript复制
                // 联表条件 默认优先匹配主键 其次带有ID结尾的名称
                var data = db.Query<Category>().Include(i => i.Products).ToList();
八、Lambda表达式

动态表达式 命名空间 Fast.Framework.Utils

代码语言:javascript复制
                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

  • 类型转换 方法名称解析示例值说明自定义函数ToStringCAST(a.[xx] AS TEXT )转换 TEXT否ToDateTimeDATETIME( a.[xx] )转换 DateTime否ToDecimalCAST(a.[xx] AS DECIMAL(10,6) )转换 DECIMAL否ToDoubleCAST(a.[xx] AS NUMERIC(10,6) )转换 NUMERIC否ToSingleCAST(a.[xx] AS FLOAT )转换 FLOAT否ToInt32CAST(a.[xx] AS INTEGER )转换 INTEGER否ToInt64CAST(a.[xx] AS BIGINT )转换 BIGINT否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 '%'||'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.[xx],'1 YEAR' )添加年份否AddMonthsDATETIME( a.[xx],'1 MONTH' )添加月份否AddDaysDATETIME( a.[xx],'1 DAY' )添加天数否AddHoursDATETIME( a.[xx],'1 HOUR' )添加时否AddMinutesDATETIME( a.[xx],'1 MINUTE' )添加分否AddSecondsDATETIME( a.[xx],'1 SECOND' )添加秒否AddMillisecondsDATETIME( a.[xx],'1 YEAR' )添加毫秒否YearSTRFTIME( '%Y', a.[xx] )获取年份是MonthSTRFTIME( '%m', a.[xx] )获取月份是DaySTRFTIME( '%j', 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是
  • 类型转换 方法名称解析示例值说明自定义函数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是
  • 类型转换 方法名称解析示例值说明自定义函数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是
  • 类型转换 方法名称解析示例值说明自定义函数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是
  • 类型转换 方法名称解析示例值说明自定义函数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.[xx] )最大值是MinMIN( a.[xx] )最小值是CountCOUNT( a.[xx] )计数是SumSUM( a.[xx] )合计是AvgAVG( a.[xx] )平均是
  • 数学函数 方法名称解析示例值说明自定义函数AbsABS( a.[xx] )绝对值是RoundROUND( a.[xx] ,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.[xx],b.[xx])日期相差是AddYearsDATEADD( YEAR,a.[xx],1 )添加年份否AddMonthsDATEADD( MONTH,a.[xx],1 )添加月份否AddDaysDATEADD( DAY,a.[xx],1 )添加天数否AddHoursDATEADD( HOUR,a.[xx],1 )添加时否AddMinutesDATEADD( MINUTE,a.[xx],1 )添加分否AddSecondsDATEADD( SECOND,a.[xx],1 )添加秒否AddMillisecondsDATEADD( MILLISECOND,a.[xx],1 )添加毫秒否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查询是
  • 其它函数 方法名称解析示例值说明自定义函数NewGuidNEWID()获取GUID否Equalsp.[ProductCode] = '123'比较否IsNullISNULL(a.[xx],0)是否为空是CaseCASEcase是WhenWHENwhen是ThenTHENthen是ElseELSEelse是EndENDend是
  • SqlServer
  • MySql
  • Oracle
  • PostgreSql
  • Sqlite

添加自定义函数解析

代码语言:javascript复制
                //注意:只能扩展未实现的方法名称 不能覆盖原有的实现
                Models.DbType.MySQL.AddSqlFunc("方法名称", (visit, method, sqlStack) =>
                {
                    //解析逻辑
                });
九、数据库日志
代码语言:javascript复制
				        db.Aop.DbLog = (sql, dp) =>
                {
                    Console.WriteLine($"执行Sql:{sql}");
                    if (dp != null)
                    {
                        foreach (var item in dp)
                        {
                            Console.WriteLine($"参数名称:{item.ParameterName} 参数值:{item.ParameterValue}");
                        }
                    }
                };
十、事务

普通事务

代码语言:javascript复制
              try
              {
                  db.Ado.BeginTran();//开启事务

                  // 执行 CRUD

                  db.Ado.CommitTran();//提交事务
              }
              catch (Exception ex)
              {
                  Console.WriteLine(ex.Message);
                  db.Ado.RollbackTran();//回滚事务
              }

更大范围的事务

代码语言:javascript复制
                try
                {
                    db.BeginTran();//开启事务

                  	// 执行 CRUD

                    db.CommitTran();//提交事务
                }
                catch (Exception ex)
                {
                    db.RollbackTran();//回滚事务
                    Console.WriteLine(ex.Message);
                }
十一、多租户

改变数据库

代码语言:javascript复制
                //数据库配置可从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
十二、原生特性支持
代码语言:javascript复制
    /// <summary>
    /// 产品
    /// </summary>
    [Table("ProductMain")]
    public class Product
    {
        /// <summary>
        /// 产品ID
        /// </summary>
        [Key]
        public int ProductId { get; set; }

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

        /// <summary>
        /// 自定义1
        /// </summary>
        [NotMapped]
        public string Custom1 { get; set; }
    }
十三、原生Ado
代码语言:javascript复制
                // 原始起步
                // 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>();
十四、工作单元

注册数据库上下文和工作单元服务

代码语言:javascript复制
var builder = WebApplication.CreateBuilder(args);

var configuration = builder.Configuration;

// 添加数据库上下文服务
builder.Services.AddFastDbContext();
// 添加工作单元服务
builder.Services.AddFastUnitOfWork();

// 加载数据库配置
builder.Services.Configure<List<DbOptions>>(configuration.GetSection("DbConfig"));

实际应用

代码语言:javascript复制
        /// <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

代码语言:javascript复制
                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);

0 人点赞