一、前言

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.FrameworkORM
Fast.Framework.Logging文件日志 (扩展项目可不使用)
Fast.Framework.DependencyInjection依赖注入 (扩展项目可不使用)
Fast.Framework.Test控制台测试项目
Fast.Framework.UnitTest单元测试项目
Fast.Framework.Web.TestWeb测试项目
三、核心对象
  • 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

      • 类型转换

        方法名称解析示例值说明自定义函数
        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' )小写
        ConcatCONCAT(a.[xx1],a.[xx2])字符串拼接
        Operation[CreateTime] >= @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] )获取天数
      • 其它函数

        方法名称解析示例值说明自定义函数
        NewGuidNEWID()获取GUID
        Equalsp.[ProductCode] = '123'比较
        IsNullISNULL(a.[xx],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`)字符串拼接
        Operation`CreateTime` >= @Now_1日期、数值、字符串范围比较
      • 日期函数

        方法名称解析示例值说明自定义函数
        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` )获取天数
      • 其它函数

        方法名称解析示例值说明自定义函数
        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")字符串拼接
        Operation”CreateTime“ >= @Now_1日期、数值、字符串范围比较
      • 日期函数

        方法名称解析示例值说明自定义函数
        YearEXTRACT( YEAR FROM a."xx" )获取年份
        MonthEXTRACT( MONTH FROM a."xx" )获取月份
        DayEXTRACT( DAY FROM a."xx" )获取天数
      • 其它函数

        方法名称解析示例值说明自定义函数
        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")字符串拼接
        Operation”CreateTime“ >= @Now_1日期、数值、字符串范围比较
      • 日期函数

        方法名称解析示例值说明自定义函数
        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.[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' )小写
        Operation[CreateTime] >= @Now_1日期、数值、字符串范围比较
      • 日期函数

        方法名称解析示例值说明自定义函数
        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] )获取天数
      • 其它函数

        方法名称解析示例值说明自定义函数
        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>
    [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);
本文来自博客园,作者:China-Mr-zhong,转载请注明原文链接:https://www.cnblogs.com/China-Mr-zhong/p/17789566.html