Fast Framework
作者 Mr-zhong
程式碼改變世界....
一、前言
Fast Framework 基於NET6.0 封裝的輕量級 ORM 框架 支援多種資料庫 SqlServer Oracle MySql PostgreSql Sqlite
優點: 體積小、原生支援微軟特性、流暢API、使用簡單、效能高、模型資料繫結採用 Expression、強大的表示式解析、支援多種子查詢可實現較為複雜查詢、原始碼可讀性強、支援AOT 編譯。
缺點:目前僅支援Db Frist
開源地址:https://github.com/China-Mr-zhong/Fast.Framework (唯一)
AOT編譯Demo:https://github.com/China-Mr-zhong/Fast.AOT.Demo
ps:此版本不再支援動態切換資料庫驅動,DbOptions 依舊支援熱過載
AOT編譯經驗分享
1.不要在方法里根據名稱去動態獲取方法資訊
2.不要使用Emit
3.不要使用dynamic 關鍵字 使用object 代替
4.配置 rd.xml 檔案
5.不要在同一個解決方案去依賴使用反射專案的類庫,需編譯後單獨引用,否則編譯有問題
二、專案明細
名稱 | 說明 |
---|---|
Fast.Framework | ORM |
Fast.Framework.Logging | 檔案日誌 (擴充套件專案可不使用) |
Fast.Framework.DependencyInjection | 依賴注入 (擴充套件專案可不使用) 不支援AOT |
Fast.Framework.Test | 控制檯測試專案 |
Fast.Framework.UnitTest | 單元測試專案 |
Fast.Framework.Web.Test | Web測試專案 |
三、核心物件
-
Ado
IAdo ado = new AdoProvider(new DbOptions() { DbId = "1", DbType = DbType.MySQL, ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout=30;" });
-
DbContext 支援多租戶
IDbContext db = new DbContext(new List<DbOptions>() { new DbOptions() { DbId = "1", DbType = DbType.MySQL, 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", "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, "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" }).UpdateColumns(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(), Max = db.Query<Category>().Max(a => a.CategoryId),//解析成Sql MaxAsync = db.Query<Category>().MaxAsync(a => a.CategoryId), Min = db.Query<Category>().Min(a => a.CategoryId),//解析成Sql MinAsync = db.Query<Category>().MinAsync(a => a.CategoryId), Count = db.Query<Category>().Count(),//解析成Sql CountAsync = db.Query<Category>().CountAsync(), Sum = db.Query<Category>().Sum(s => s.CategoryId),//解析成Sql SumAsync = db.Query<Category>().SumAsync(s => s.CategoryId), Avg = db.Query<Category>().Avg(s => s.CategoryId),//解析成Sql AvgAsync = db.Query<Category>().AvgAsync(s => s.CategoryId) }); var data2= query.First();
-
From子查詢
var subQuery2 = db.Query<Product>().Select(s=>new { s.ProductId, s.CategoryId, s.ProductCode, s.ProductName, s.DeleteMark }); var data = db.Query(subQuery2).ToList();
-
Join子查詢
var subQuery1 = db.Query<Product>().Select(s => new { s.ProductId, s.CategoryId, s.ProductCode, s.ProductName, s.DeleteMark }); var data = db.Query<Category>().InnerJoin(subQuery1, (a, b) => a.CategoryId == b.CategoryId).ToList();
-
Include查詢
// 聯表條件 預設優先匹配主鍵 其次帶有ID結尾的名稱 var data = db.Query<Category>().Include(i => i.Products).ToList();
-
Exists查詢
var data = db.Query<Product>() .Where(w => db.Query<Product>().WhereIF(!string.IsNullOrWhiteSpace("測試"), a => a.ProductId == 1).Select(s => 1).Any()) .Select(s => new { s.ProductId, s.ProductCode }).ToList();
-
查詢繫結欄位(注意 欄位必須是公開的,否則繫結外部無法訪問,沒有意義)
//當某些欄位需要參與計算並且不返回前端時推薦用欄位繫結,無需從A實體轉換到B實體,強烈推薦此方式 var data = db.Query<Product>().Select(s => new Product() { _xx = s.ProductName }).First();
八、Lambda表示式
-
動態表示式 名稱空間 Fast.Framework.Utils
var ex = DynamicWhereExp.Create<Product>().AndIF(1 == 1, a => a.DeleteMark == true).Build(); var data = db.Query<Product>().Where(ex).ToList();
-
Sql函式 自定義函式 需引入名稱空間 Fast.Framework.Utils 使用SqlFunc類
-
SqlServer
-
型別轉換
方法名稱 解析示例值 說明 自定義函式 ToString CONVERT( VARCHAR(255),123) 轉換 VARCHAR 否 ToDateTime CONVERT( DATETIME,‘2022-09-16’) 轉換 DATETIME 否 ToDecimal CONVERT( DECIMAL(10,6),‘123’) 轉換 DECIMAL 否 ToDouble CONVERT( NUMERIC(10,6),‘123’) 轉換 NUMERIC 否 ToSingle CONVERT( FLOAT,‘123’) 轉換 FLOAT 否 ToInt32 CONVERT( INT,‘123’) 轉換 INT 否 ToInt64 CONVERT( BIGINT,‘123’) 轉換 BIGINT 否 ToBoolean CONVERT( BIT,‘1’) 轉換 BIT 否 ToChar CONVERT( CHAR(2),'x') 轉換 CHAR 否 -
聚合函式
方法名稱 解析示例值 說明 自定義函式 Max MAX( a.[xx] ) 最大值 是 Min MIN( a.[xx] ) 最小值 是 Count COUNT( a.[xx] ) 計數 是 Sum SUM( a.[xx] ) 合計 是 Avg AVG( a.[xx] ) 平均 是 -
數學函式
方法名稱 解析示例值 說明 自定義函式 Abs ABS( a.[xx] ) 絕對值 是 Round ROUND( a.[xx] ,2 ) 四捨五入 是 -
字串函式
方法名稱 解析示例值 說明 自定義函式 StartsWith LIKE 'xx'+‘%’ 左模糊 否 EndsWith LIKE ‘%’+'xx' 右模糊 否 Contains LIKE ‘%’+'xx'+‘%’ 全模糊 否 SubString SUBSTRING( 'xxxxxx' ,1,3) 擷取 否 Replace REPLACE( 'xxx','x','y') 替換 否 Len LEN( 'xxx' ) 長度 是 TrimStart LTRIM( ' xx ' ) 修剪起始空格 否 TrimEnd RTRIM( ' xx ' ) 修剪末尾空格 否 ToUpper UPPER( 'xx' ) 大寫 否 ToLower LOWER( 'xx' ) 小寫 否 Concat CONCAT(a.[xx1],a.[xx2]) 字串拼接 否 Operation [CreateTime] >= @Now_1 日期、數值、字串範圍比較 是 -
日期函式
方法名稱 解析示例值 說明 自定義函式 DateDiff DATEDIFF( DAY ,a.[xx],b.[xx]) 日期相差 是 AddYears DATEADD( YEAR,a.[xx],1 ) 新增年份 否 AddMonths DATEADD( MONTH,a.[xx],1 ) 新增月份 否 AddDays DATEADD( DAY,a.[xx],1 ) 新增天數 否 AddHours DATEADD( HOUR,a.[xx],1 ) 新增時 否 AddMinutes DATEADD( MINUTE,a.[xx],1 ) 新增分 否 AddSeconds DATEADD( SECOND,a.[xx],1 ) 新增秒 否 AddMilliseconds DATEADD( MILLISECOND,a.[xx],1 ) 新增毫秒 否 Year YEAR( a.[xx] ) 獲取年份 是 Month MONTH( a.[xx] ) 獲取月份 是 Day DAY( a.[xx] ) 獲取天數 是 -
其它函式
方法名稱 解析示例值 說明 自定義函式 NewGuid NEWID() 獲取GUID 否 Equals p.[ProductCode] = '123' 比較 否 IsNull ISNULL(a.[xx],0) 是否為空 是 Case CASE case 是 When WHEN when 是 Then THEN then 是 Else ELSE else 是 End END end 是
-
-
MySql
-
型別轉換
方法名稱 解析示例值 說明 自定義函式 ToString CAST( a.`xx` AS CHAR(510) ) 轉換 CHAR(510) 否 ToDateTime CAST( a.`xx` AS DATETIME ) 轉換 DATETIME 否 ToDecimal CAST( a.`xx` AS DECIMAL(10,6) ) 轉換 DECIMAL(10,6) 否 ToDouble CAST( a.`xx` AS DECIMAL(10,6) ) 轉換 DECIMAL(10,6) 否 ToInt32 CAST( a.`xx` AS DECIMAL(10) ) 轉換 DECIMAL(10) 否 ToInt64 CAST( a.`xx` AS DECIMAL(19) ) 轉換 DECIMAL(19) 否 ToBoolean CAST( a.`xx` AS UNSIGNED ) 轉換 UNSIGNED 否 ToChar CAST( a.`xx` AS CHAR(2) ) 轉換 CHAR(2) 否 -
聚合函式
方法名稱 解析示例值 說明 自定義函式 Max MAX( a.`xx` ) 最大值 是 Min MIN( a.`xx` ) 最小值 是 Count COUNT( a.`xx` ) 計數 是 Sum SUM( a.`xx` ) 合計 是 Avg AVG( a.`xx` ) 平均 是 -
數學函式
方法名稱 解析示例值 說明 自定義函式 Abs ABS( a.`xx` ) 絕對值 是 Round ROUND( a.`xx` ,2 ) 四捨五入 是 -
字串函式
方法名稱 解析示例值 說明 自定義函式 StartsWith LIKE CONCAT( 'xx','%' ) 左模糊 否 EndsWith LIKE CONCAT( '%','xx' ) 右模糊 否 Contains LIKE CONCAT( '%','xx','%' ) 全模糊 否 SubString SUBSTRING( 'xxxxxx' ,1,3 ) 擷取 否 Replace REPLACE( 'xxx','x','y' ) 替換 否 Len LEN( 'xxx' ) 長度 是 Trim TRIM( ' xx ' ) 修剪空格 否 TrimStart LTRIM( ' xx ' ) 修剪起始空格 否 TrimEnd RTRIM( ' xx ' ) 修剪末尾空格 否 ToUpper UPPER( 'xx' ) 大寫 否 ToLower LOWER( 'xx' ) 小寫 否 Concat CONCAT(a.`xx1`,a.`xx2`) 字串拼接 否 Operation `CreateTime` >= @Now_1 日期、數值、字串範圍比較 是 -
日期函式
方法名稱 解析示例值 說明 自定義函式 DateDiff DATEDIFF( a.`xx`,b.`xx` ) 日期相差 返回相差天數 是 TimestampDiff TIMESTAMPDIFF( DAY,a.`xx`,b.`xx` ) 日期相差 指定時間單位 是 AddYears DATE_ADD( a.`xx`,INTERVAL 1 YEAR ) 新增年份 否 AddMonths DATE_ADD( a.`xx`,INTERVAL 1 MONTH ) 新增月份 否 AddDays DATE_ADD( a.`xx`,INTERVAL 1 DAY ) 新增天數 否 AddHours DATE_ADD( a.`xx`,INTERVAL 1 HOUR ) 新增時 否 AddMinutes DATE_ADD( a.`xx`,INTERVAL 1 MINUTE ) 新增分 否 AddSeconds DATE_ADD( a.`xx`,INTERVAL 1 SECOND ) 新增秒 否 AddMilliseconds DATE_ADD( a.`xx`,INTERVAL 1 MINUTE_SECOND ) 新增毫秒 否 Year YEAR( a.`xx` ) 獲取年份 是 Month MONTH( a.`xx` ) 獲取月份 是 Day DAY( a.`xx` ) 獲取天數 是 -
其它函式
方法名稱 解析示例值 說明 自定義函式 NewGuid UUID() 獲取GUID 否 Equals p.`ProductCode` = '123' 比較 否 IfNull IFNULL( a.`xx`,0 ) 如果為空 是 Case CASE case 是 When WHEN when 是 Then THEN then 是 Else ELSE else 是 End END end 是
-
-
Oracle
-
型別轉換
方法名稱 解析示例值 說明 自定義函式 ToString CAST( a."xx" AS VARCHAR(255) ) 轉換 VARCHAR 否 ToDateTime TO_TIMESTAMP( a."xx" ,'yyyy-MM-dd hh:mi:ss.ff') 轉換 DATETIME 否 ToDecimal CAST( a."xx" AS DECIMAL(10,6) ) 轉換 DECIMAL 否 ToDouble CAST( a."xx" AS NUMBER ) 轉換 NUMBER 否 ToSingle CAST( a."xx" AS FLOAT ) 轉換 FLOAT 否 ToInt32 CAST( a."xx" AS INT ) 轉換 INT 否 ToInt64 CAST( a."xx" AS NUMBER ) 轉換 NUMBER 否 ToBoolean CAST( a."xx" AS CHAR(1) ) 轉換 CHAR 否 ToChar CAST( a."xx" AS CHAR(2) ) 轉換 CHAR 否 -
聚合函式
方法名稱 解析示例值 說明 自定義函式 Max MAX( a."xx" ) 最大值 是 Min MIN( a."xx" ) 最小值 是 Count COUNT( a."xx" ) 計數 是 Sum SUM( a."xx" ) 合計 是 Avg AVG( a."xx" ) 平均 是 -
數學函式
方法名稱 解析示例值 說明 自定義函式 Abs ABS( a."xx" ) 絕對值 是 Round ROUND( a."xx" ,2 ) 四捨五入 是 -
字串函式
方法名稱 解析示例值 說明 自定義函式 StartsWith LIKE CONCAT( 'xx','%' ) 左模糊 否 EndsWith LIKE CONCAT( '%','xx' ) 右模糊 否 Contains LIKE CONCAT( '%','xx','%' ) 全模糊 否 SubString SUBSTRING( 'xxxxxx' ,1,3) 擷取 否 Replace REPLACE( 'xxx','x','y') 替換 否 Length LENGTH( 'xxx' ) 長度 是 TrimStart LTRIM( ' xx ' ) 修剪起始空格 否 TrimEnd RTRIM( ' xx ' ) 修剪末尾空格 否 ToUpper UPPER( 'xx' ) 大寫 否 ToLower LOWER( 'xx' ) 小寫 否 Concat CONCAT(a."xx1",a."xx2") 字串拼接 否 Operation ”CreateTime“ >= @Now_1 日期、數值、字串範圍比較 是 -
日期函式
方法名稱 解析示例值 說明 自定義函式 Year EXTRACT( YEAR FROM a."xx" ) 獲取年份 是 Month EXTRACT( MONTH FROM a."xx" ) 獲取月份 是 Day EXTRACT( DAY FROM a."xx" ) 獲取天數 是 -
其它函式
方法名稱 解析示例值 說明 自定義函式 Equals p."ProductCode" = '123' 比較 否 Nvl NVL( a."xx",0 ) 空,預設 是 Case CASE case 是 When WHEN when 是 Then THEN then 是 Else ELSE else 是 End END end 是
-
-
PostgreSql
-
型別轉換
方法名稱 解析示例值 說明 自定義函式 ToString a."xx"::VARCHAR(255) 轉換 VARCHAR 否 ToDateTime a."xx"::TIMESTAMP 轉換 TIMESTAMP 否 ToDecimal a."xx"::DECIMAL(10,6) 轉換 DECIMAL 否 ToDouble a."xx"::NUMERIC(10,6) 轉換 NUMERIC 否 ToSingle a."xx"::REAL 轉換 REAL 否 ToInt32 a."xx"::INTEGER 轉換 INT 否 ToInt64 a."xx"::BIGINT 轉換 BIGINT 否 ToBoolean a."xx"::BOOLEAN 轉換 BOOLEAN 否 ToChar a."xx"::CHAR(2) 轉換 CHAR 否 -
聚合函式
方法名稱 解析示例值 說明 自定義函式 Max MAX( a."xx" ) 最大值 是 Min MIN( a."xx" ) 最小值 是 Count COUNT( a."xx" ) 計數 是 Sum SUM( a."xx" ) 合計 是 Avg AVG( a."xx" ) 平均 是 -
數學函式
方法名稱 解析示例值 說明 自定義函式 Abs ABS( a."xx" ) 絕對值 是 Round ROUND( a."xx" ,2 ) 四捨五入 是 -
字串函式
方法名稱 解析示例值 說明 自定義函式 StartsWith LIKE CONCAT( '%','xx' ) 左模糊 否 EndsWith LIKE CONCAT( 'xx','%' ) 右模糊 否 Contains LIKE CONCAT( '%','xx','%' ) 全模糊 否 SubString SUBSTRING( 'xxxxxx' ,1,3 ) 擷取 否 Replace REPLACE( 'xxx','x','y' ) 替換 否 Length LENGTH( 'xxx' ) 長度 是 Trim TRIM( ' xx ' ) 修剪空格 否 TrimStart LTRIM( ' xx ' ) 修剪起始空格 否 TrimEnd RTRIM( ' xx ' ) 修剪末尾空格 否 ToUpper UPPER( 'xx' ) 大寫 否 ToLower LOWER( 'xx' ) 小寫 否 Concat CONCAT(a."xx1",a."xx2") 字串拼接 否 Operation ”CreateTime“ >= @Now_1 日期、數值、字串範圍比較 是 -
日期函式
方法名稱 解析示例值 說明 自定義函式 AddYears a."xx" + INTERVAL '1 YEAR' 新增年份 否 AddMonths a."xx" + INTERVAL '1 MONTH' 新增月份 否 AddDays a."xx" + INTERVAL '1 DAY' 新增天數 否 AddHours a."xx" + INTERVAL '1 HOUR' 新增時 否 AddMinutes a."xx" + INTERVAL '1 MINUTE' 新增分 否 AddSeconds a."xx" + INTERVAL '1 SECOND' 新增秒 否 AddMilliseconds a."xx" + INTERVAL '1 MINUTE_SECOND' 新增毫秒 否 Year YEAR( a."xx" ) 獲取年份 是 Month MONTH( a."xx" ) 獲取月份 是 Day DAY( a."xx" ) 獲取天數 是 -
查詢函式
方法名稱 解析示例值 說明 自定義函式 In IN ( a."xx" ,'x1','x2','x3' ) In查詢 是 NotIn NOT IN ( a."xx" ,'x1','x2','x3' ) Not In查詢 是 -
其它函式
方法名稱 解析示例值 說明 自定義函式 Equals p.”ProductCode“ = '123' 比較 否 Case CASE case 是 When WHEN when 是 Then THEN then 是 Else ELSE else 是 End END end 是
-
-
Sqlite
-
型別轉換
方法名稱 解析示例值 說明 自定義函式 ToString CAST(a.[xx] AS TEXT ) 轉換 TEXT 否 ToDateTime DATETIME( a.[xx] ) 轉換 DateTime 否 ToDecimal CAST(a.[xx] AS DECIMAL(10,6) ) 轉換 DECIMAL 否 ToDouble CAST(a.[xx] AS NUMERIC(10,6) ) 轉換 NUMERIC 否 ToSingle CAST(a.[xx] AS FLOAT ) 轉換 FLOAT 否 ToInt32 CAST(a.[xx] AS INTEGER ) 轉換 INTEGER 否 ToInt64 CAST(a.[xx] AS BIGINT ) 轉換 BIGINT 否 ToBoolean CAST(a.[xx] AS CHAR(1) ) 轉換 CHAR 否 ToChar CAST(a.[xx] AS CHAR(2) ) 轉換 CHAR 否 -
聚合函式
方法名稱 解析示例值 說明 自定義函式 Max MAX( a.[xx] ) 最大值 是 Min MIN( a.[xx] ) 最小值 是 Count COUNT( a.[xx] ) 計數 是 Sum SUM( a.[xx] ) 合計 是 Avg AVG( a.[xx] ) 平均 是 -
數學函式
方法名稱 解析示例值 說明 自定義函式 Abs ABS( a.[xx] ) 絕對值 是 Round ROUND( a.[xx] ,2 ) 四捨五入 是 -
字串函式
方法名稱 解析示例值 說明 自定義函式 StartsWith LIKE 'xx'||'%' 左模糊 否 EndsWith LIKE '%'||'xx' 否 Contains LIKE '%'||'xx'||'%' 全模糊 否 SubString SUBSTRING( 'xxxxxx' ,1,3 ) 擷取 否 Replace REPLACE( 'xxx','x','y' ) 替換 否 Length LENGTH( 'xxx' ) 長度 是 Trim TRIM( ' xx ' ) 修剪空格 否 TrimStart LTRIM( ' xx ' ) 修剪起始空格 否 TrimEnd RTRIM( ' xx ' ) 修剪末尾空格 否 ToUpper UPPER( 'xx' ) 大寫 否 ToLower LOWER( 'xx' ) 小寫 否 Operation [CreateTime] >= @Now_1 日期、數值、字串範圍比較 是 -
日期函式
方法名稱 解析示例值 說明 自定義函式 AddYears DATETIME( a.[xx],'1 YEAR' ) 新增年份 否 AddMonths DATETIME( a.[xx],'1 MONTH' ) 新增月份 否 AddDays DATETIME( a.[xx],'1 DAY' ) 新增天數 否 AddHours DATETIME( a.[xx],'1 HOUR' ) 新增時 否 AddMinutes DATETIME( a.[xx],'1 MINUTE' ) 新增分 否 AddSeconds DATETIME( a.[xx],'1 SECOND' ) 新增秒 否 AddMilliseconds DATETIME( a.[xx],'1 YEAR' ) 新增毫秒 否 Year STRFTIME( '%Y', a.[xx] ) 獲取年份 是 Month STRFTIME( '%m', a.[xx] ) 獲取月份 是 Day STRFTIME( '%j', a.[xx] ) 獲取天數 是 -
其它函式
方法名稱 解析示例值 說明 自定義函式 Equals p.”ProductCode“ = '123' 比較 否 Case CASE case 是 When WHEN when 是 Then THEN then 是 Else ELSE else 是 End END end 是
-
-
-
新增自定義函式解析
//注意:只能擴充套件未實現的方法名稱 不能覆蓋原有的實現 Models.DbType.MySQL.AddSqlFunc("方法名稱", (visit, method, sqlStack) => { //解析邏輯 });
九、資料庫日誌
db.Aop.DbLog = (sql, dp) =>
{
Console.WriteLine($"執行Sql:{sql}");
if (dp != null)
{
foreach (var item in dp)
{
Console.WriteLine($"引數名稱:{item.ParameterName} 引數值:{item.ParameterValue}");
}
}
};
十、事務
-
普通事務
try { db.Ado.BeginTran();//開啟事務 // 執行 CRUD db.Ado.CommitTran();//提交事務 } catch (Exception ex) { Console.WriteLine(ex.Message); db.Ado.RollbackTran();//回滾事務 }
-
更大範圍的事務
try { db.BeginTran();//開啟事務 // 執行 CRUD db.CommitTran();//提交事務 } catch (Exception ex) { db.RollbackTran();//回滾事務 Console.WriteLine(ex.Message); }
十一、多租戶
-
改變資料庫
//資料庫配置可從Json配置檔案載入 IDbContext db = new DbContext(new List<DbOptions>() { new DbOptions() { DbId = "1", DbType = Models.DbType.SQLServer, 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, 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);