EFCore是.NETCore團隊開發的一個ORM組件,但這個組件在執行傳統SQL的時候並不方便,因此BeetleX.EFCore.Extension的設計目的是讓EFCore執行傳統SQL更簡單方便。
引用
在使用組件之前需要引用它,可以通過以下地址獲取最新版本:https://www.nuget.org/packages/BeetleX.EFCore.Extension/
使用
引用組件后就可以使用,組件的操作操作都是針對EFCore的DBContext對象來進行數據庫操作。
SQL sql = "select * from employees"; var employees = sql.List<Employee, NorthwindContext>();
組件提供SQL對象用來操作傳統的SQL語句,以上代碼是在NorthwindContext數據庫上執行查詢語句並返回相關信息列表。
sql = "select * from customers where country=@country"; sql += ("@country", "UK"); var customers = sql.List<Customer, NorthwindContext>();
以上是針對參數化的SQL處理,在操作上DBContext可以通過泛參傳入或通過實例以變量的參數傳入,通過泛參傳入的好處是不用實例化DBContext。
批量更新
在EFCore更新某個條件的字段信息操作起來比較麻煩,所以組件也擴展出相關方法來解決。
using (NorthwindContext db = new NorthwindContext()) { db.Customers.Where(c => c.CustomerID == "ken") .Update(c => new Customer { City="GZ" }); }
以上操作是把國家是UK的所有記錄Region改成uk
批量刪除
同樣EFCore在批條件刪除上也不怎么方便,組件同樣也在DBSet的基礎上擴展了Delete批刪除方法.
using (NorthwindContext db = new NorthwindContext()) { db.Customers.Where(c => c.CustomerID == "ken") .Delete(); }
以上是刪除國家是UK的所有記錄.
Select對象
Select對象是針對單個表的個性查詢需求制定的,它可以定義查詢不同的定段和條件來返回到指定的對象中。
class CustomerName { public string CustomerID { get; set; } public string CompanyName { get; set; } } [Fact] Select<Customer> select = new Select<Customer>("CustomerID", "CompanyName"); select &= c => c.Country == "UK"; var items = select.List<CustomerName, NorthwindContext>();
以上是針對客戶信息查詢一些字段並返回到其他結構的對象列表中。
SQL對象
為了讓字符的Sql語句處理更方便,所以組針對Sql語句封了一個對象。該對象主要用於執行Sql語句並返回結果,它的主要作用是簡單化DbCommand的處理。在這基礎上提供參數化處理,查詢支持返回固定類型和動態類型,支持同步和異步操作等。
定義對象
該對象支持直接從String轉義,所以在定義的時候可以直接指向一個Sql的字符串。
SQL sql = "select * from customers";
以上是定義一個客戶查詢的SQL對象,定義完成后就可以進行相關查詢操作,它提供了Execute,ExecuteScalar,ListFirst和List方法,分別是返回符合查詢的第一個對象和返回符查詢條件某個區中的對象;以上兩個方法都支持異步ExecuteAsync,ExecuteScalarAsync,ListFirstAsync和ListAsync,並支持多個重載版本可操作。
ListFirst
public T ListFirst<T, DB>() where DB : DbContext, new() public T ListFirst<T>(DbContext db) where T : new() public Task<T> ListFirstAsync<T, DB>() where DB : DbContext, new() where T : new() public async Task<T> ListFirstAsync<T>(DbContext db) where T : new()
T可以是任意對象類型,組件會自動做字段和屬性匹配;DbContext支持兩種方式提供,一種基於泛參在這情況下對應DbContext必須提供默認構建函數;別一種則直接通參數傳入對應的實例對象。
List
public IList<T> List<T, DB>(Region region = null) where T : new() where DB : DbContext, new() public IList<T> List<T>(DbContext db, Region region = null) where T : new() public void List(DbContext db, Region region, Action<IDataReader> handler) public async Task<IList<T>> ListAsync<T, DB>(Region region = null) where T : new() where DB : DbContext, new() public async Task<IList<T>> ListAsync<T>(DbContext db, Region region = null) where T : new() public async Task ListAsync(DbContext db, Region region, Action<IDataReader> handler)
T可以是任意對象類型,組件會自動做字段和屬性匹配;DbContext支持兩種方式提供,一種基於泛參在這情況下對應DbContext必須提供默認構建函數;別一種則直接通參數傳入對應的實例對象。region是缺省參數用於指定加載那個區間的數據,默認不指定的情況下組件只加載100條數據。
SQL sql = "select * from customers"; var customers = sql.List<Customer, NorthwindContext>(); customers = await sql.ListAsync<Customer, NorthwindContext>();
動態類型
有很多時候只查詢個別字段,但又不可以定義相關結構對象的情況下可以使用動態類型傳入.
SQL sql = "select CustomerID,CompanyName from customers"; var items=sql.List<ExpandoObject, NorthwindContext>(); foreach(dynamic item in items) { Console.WriteLine(item.CustomerID); }
可以通過ExpandoObject作為動態類型對象傳入,后繼通過dynamic定義操作即可.
分頁獲取
雖然在查詢過程中提供了Region參數用於獲取某個區間的數據,但在分頁應用中還是需要統計總數和頁數的處理,為了簡化這個操作組件封了DBRegionData<T>對象來簡化這操作.
SQL sql = "select * from customers"; DBRegionData<Customer> region = new DBRegionData<Customer>(0, 20); await region.ExecuteAsync<NorthwindContext>(sql); foreach (var item in region.Items) { Console.WriteLine(item.CompanyName); }
以上示例是按20條來分頁,獲取第一頁的數據。DBRegionData<T>提供了Count,Pages,Index和Items等屬性可提供訪問。
拼裝和參數化
在編寫Sql語句的時候往往都不能一條寫完,很多時候針對不同的條件來組裝語句;SQL對象重寫了運算符直接支持和String相加的處理。
SQL sql = "select * from customers where 1=1"; sql += " and country=@country"; sql += ("@country", "UK"); Console.WriteLine(sql.Count<NorthwindContext>());
SQL支持和String直接相加,參數變量也是通過加的方式來添加,只是對應參數必須以ValueTask<string,object>的方式編寫。
表達式條件
對於直接用String來拼接Sql語句容易出錯,那可以采用對象提供的表達式來進行條件增加處理;這種處理方式的好處是不容易寫錯字段名稱和參數化的處理。
SQL sql = "select * from orders where 1=1"; sql.And().Where<Order>((o) => o.EmployeeID == 3 && o.CustomerID == "henry");
對象提供了Where方法來編寫條件表達式,該表達式支持多類型傳入處理。
SQL sql = "select * from orders where 1=1"; sql.And().Where<Order>((o) => o.EmployeeID == 3 && o.CustomerID == "henry"); sql.OrderBy<Order>(o => o.OrderDate.ASC());
同樣排序方式也可以通過表達式的方式來添加.
轉義對象
DBObjectList<T>,DBValueList<T>DBExecute<T>和DBExecute都支持轉義操作,對應的結構是ValueTuple<DbContext, SQL>.在轉義過程中組件可支持執行處理。
using (NorthwindContext db = new NorthwindContext()) { SQL sql = "select * from customers"; DBObjectList<Customer> customers = (db, sql); sql = "select CustomerID,CompanyName from customers"; DBObjectList<ExpandoObject> names = (db, sql); sql = "select count(*) from customers"; DBValueList<long> count = (db, sql); }
事務
SQL對象無須針對事務做任何設置,它的事務開啟主要是由對應的DbContext對象所決定的。
執行鏈跟蹤
在新版中添加了執行跟蹤鏈,可以進一步查看組件執行SQL的情況。
using (CodeTrackFactory.TrackReport("AutoExecute", CodeTrackLevel.Bussiness, null, "EFCore", "BeetleX")) { using (NorthwindContext db = new NorthwindContext()) { DBValueList<string> values = (db, "select customerid from customers"); DBObjectList<CustomerName> items = (db, "select CustomerID,CompanyName from customers"); DBExecute<string> id = (db, "select CompanyName from customers where CustomerID='ALFKI'"); var item = db.Customers.Where(c => c.CustomerID == "AROUT").FirstOrDefault(); item.Region = "GuangZhou"; db.SaveChanges(); } } Console.WriteLine(CodeTrackFactory.Activity?.GetReport());