輕量ORM-SqlRepoEx (十四)最佳實踐之Dapper(1)
簡介:SqlRepoEx是 .Net平臺下相容.NET Standard 2.0人一個輕型的ORM。解決了Lambda轉Sql語句這一難題,SqlRepoEx使用的是Lambda表示式,所以,對c#程式設計師來說,是非常簡單的,其語法特點與Linq to Sql極為相似。不僅實現了完整的Select、Insert、Update、Delete等語句解析器,同時,也實現了Select、where、order by等子句,這些語句與子句均支援匯出SQL語句,使得拼接複雜場景SQL語句變得輕鬆,SqlRepoEx很快其原生資料訪問與Dapper不相上下,SqlRepoEx本身支援Sql Server與MySql方言,同時通過SqlRepoEx.Normal支援非方言SQL。SqlRepoEx沒侵入性,僅通過簡單的幾個特性,就能讓類與資料庫關聯起來;
*本系列以靜態工廠為例;
*資料來源於Northwind資料庫;
一、IDbConnection
可通過下列兩種方式獲取
1、工廠獲取
private static IDbConnection dbConnection = MsSqlRepoFactory.DbConnection;
2、資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
IDbConnection dbConnection = repository.DbConnection;
二、 SQL語句中 @ 引數的生成和定義
1、SqlRepoEx的Insert、Updata 增加了ParamSql()方法獲取 @ 引數 語句;
2、對於Where條件語句中,如要生成 @ 引數 語句 只需要在表示式中 .Where(p => p.ProductID == p.ProductID);右側表示式中使用型別屬性表示式即可。
3、關於資料欄位與屬性聯,將在下篇中介紹
三、 簡單查詢
public static void QueryOnly()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
//查詢
var result = repository.Query().Top(10);
Console.WriteLine(result.Sql());
// 通過 Dapper 獲取資料
IEnumerable<AzProducts> azProducts = dbConnection.Query<AzProducts>(result.Sql());
// 顯示結果(只取兩列,僅為顯示目的)
foreach (var item in azProducts)
{
Console.WriteLine($"{item.ProductID}\t{item.ProductName2}");
}
}
此方法生成的 SQL
SELECT TOP (10) [dbo].[Products].[ProductID]
, [dbo].[Products].[ProductName] as [ProductName2]
, [dbo].[Products].[SupplierID]
, [dbo].[Products].[CategoryID]
, [dbo].[Products].[QuantityPerUnit]
, [dbo].[Products].[UnitPrice]
, [dbo].[Products].[UnitsInStock]
, [dbo].[Products].[UnitsOnOrder]
, [dbo].[Products].[ReorderLevel]
, [dbo].[Products].[Discontinued]
FROM [dbo].[Products];
此方法生成的結果
1 Chai
2 Chang
3 Aniseed Syrup
4 Chef Anton's Cajun Seasoning
5 Chef Anton's Gumbo Mix
6 Grandma's Boysenberry Spread
7 Uncle Bob's Organic Dried Pears
8 Northwoods Cranberry Sauce
9 Mishi Kobe Niku
10 Ikura
四、InnerJoin 查詢
* LeftOuterJoin、RightOuterJoin與此例相似
public static void DoInnerJoin()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
// 構建查詢語句,相較而言,語法更接近於SQL,與Linq是有很大區別的
var result = repository.Query()
.InnerJoin<AzSuppliers>()
.On<AzSuppliers>((l, r) => l.SupplierID == r.SupplierID, r => r.CompanyName)
.Top(10);
Console.WriteLine(result.Sql());
Console.WriteLine();
// 通過 Dapper 獲取資料
IEnumerable<AzProducts> azProducts = dbConnection.Query<AzProducts>(result.Sql());
foreach (var item in azProducts)
{
Console.WriteLine($"{item.ProductID}\t{item.ProductName2}\t{item.Supplier}");
}
}
此方法生成的 SQL
SELECT TOP (10) [dbo].[Products].[ProductID]
, [dbo].[Products].[ProductName] as [ProductName2]
, [dbo].[Products].[SupplierID]
, [dbo].[Products].[CategoryID]
, [dbo].[Products].[QuantityPerUnit]
, [dbo].[Products].[UnitPrice]
, [dbo].[Products].[UnitsInStock]
, [dbo].[Products].[UnitsOnOrder]
, [dbo].[Products].[ReorderLevel]
, [dbo].[Products].[Discontinued]
, [dbo].[Suppliers].[CompanyName] as [Supplier]
FROM [dbo].[Products]
INNER JOIN [dbo].[Suppliers]
ON [dbo].[Products].[SupplierID] = [dbo].[Suppliers].[SupplierID];
此方法生成的結果
1 Chai Exotic Liquids
2 Chang Exotic Liquids
3 Aniseed Syrup Exotic Liquids
4 Chef Anton's Cajun Seasoning New Orleans Cajun Delights
5 Chef Anton's Gumbo Mix New Orleans Cajun Delights
6 Grandma's Boysenberry Spread Grandma Kelly's Homestead
7 Uncle Bob's Organic Dried Pears Grandma Kelly's Homestead
8 Northwoods Cranberry Sauce Grandma Kelly's Homestead
9 Mishi Kobe Niku Tokyo Traders
10 Ikura Tokyo Traders
五、條件查詢
public static void QueryWhere()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
var result = repository.Query()
.Where(p => p.ProductName2.Contains("t") && p.ProductID < 100)
.Top(10);
Console.WriteLine(result.Sql());
Console.WriteLine();
// 通過 Dapper 獲取資料
IEnumerable<AzProducts> azProducts = dbConnection.Query<AzProducts>(result.Sql());
foreach (var item in azProducts)
{
Console.WriteLine($"{item.ProductID}\t{item.ProductName2}");
}
}
此方法生成的 SQL
SELECT TOP (10) [dbo].[Products].[ProductID]
, [dbo].[Products].[ProductName] as [ProductName2]
, [dbo].[Products].[SupplierID]
, [dbo].[Products].[CategoryID]
, [dbo].[Products].[QuantityPerUnit]
, [dbo].[Products].[UnitPrice]
, [dbo].[Products].[UnitsInStock]
, [dbo].[Products].[UnitsOnOrder]
, [dbo].[Products].[ReorderLevel]
, [dbo].[Products].[Discontinued]
FROM [dbo].[Products]
WHERE ((([dbo].[Products].[ProductName] LIKE '%t%') and ([dbo].[Products].[ProductID] < 100)));
此方法生成的結果
4 Chef Anton's Cajun Seasoning
5 Chef Anton's Gumbo Mix
8 Northwoods Cranberry Sauce
12 Queso Manchego La Pastora
14 Tofu
17 Alice Mutton
18 Carnarvon Tigers
19 Teatime Chocolate Biscuits
22 Gustaf's Kn?ckebr?d
23 Tunnbr?d
六、Union
public static void QueryUnion()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzCustomers>();
// 此語句不會參與資料查詢,只是作為Union的包裹
// 如果此語句本身也是資料查詢,請增加到new List<UnionSql>中
var result = repository.Query()
.Select(c => c.CustomerID, c => c.CompanyName);
var result01 = repository.Query()
.Select(c => c.CustomerID, c => c.CompanyName)
.Where(c => c.CustomerID == "ANATR");
var result02 = repository.Query()
.Select(c => c.CustomerID, c => c.CompanyName)
.Where(c => c.CustomerID == "FRANK");
var result03 = repository.Query()
.Select(c => c.CustomerID, c => c.CompanyName)
.Where(c => c.CustomerID == "TRADH");
var resultAllSql = result.UnionSql(new List<UnionSql> {
UnionSql.New( result01,UnionType.Union ),
UnionSql.New( result02,UnionType.Union ),
UnionSql.New( result03,UnionType.Union ), });
Console.WriteLine(resultAllSql);
Console.WriteLine();
// 通過 Dapper 獲取資料
IEnumerable<AzCustomers> azCustomers = dbConnection.Query<AzCustomers>(resultAllSql);
foreach (var item in azCustomers)
{
Console.WriteLine($"{item.CustomerID}\t{item.CompanyName}");
}
}
此方法生成的 SQL
SELECT [_this_is_union].[CustomerID]
, [_this_is_union].[CompanyName]
FROM ( SELECT [dbo].[Customers].[CustomerID]
, [dbo].[Customers].[CompanyName]
FROM [dbo].[Customers]
WHERE (([dbo].[Customers].[CustomerID] = 'ANATR'))
UNION
SELECT [dbo].[Customers].[CustomerID]
, [dbo].[Customers].[CompanyName]
FROM [dbo].[Customers]
WHERE (([dbo].[Customers].[CustomerID] = 'FRANK'))
UNION
SELECT [dbo].[Customers].[CustomerID]
, [dbo].[Customers].[CompanyName]
FROM [dbo].[Customers]
WHERE (([dbo].[Customers].[CustomerID] = 'TRADH')) )
AS _this_is_union
此方法生成的結果
ANATR Ana Trujillo Emparedados y helados
FRANK Frankenversand
TRADH Tradi??o Hipermercados
七、增加(使用例項)
public static void DoInsertEntityParam()
{
var repository = MsSqlRepoFactory.Create<AzProducts>();
AzProducts azProduct = new AzProducts { ProductName2 = "testvalue" };
var resultinsert = repository
.Insert();
// 使用ParamSql()方法獲取 @ 引數SQL語句
Console.WriteLine(resultinsert.ParamSql());
Console.WriteLine();
// 需返回自增欄位,所以用Query
IEnumerable<AzProducts> azProducts = dbConnection.Query<AzProducts>(resultinsert.ParamSql(), azProduct);
foreach (var item in azProducts)
{
Console.WriteLine($"{item.ProductID}\t{item.ProductName2}");
}
}
此方法生成的 SQL
INSERT [dbo].[Products]([ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued])
VALUES(@ProductName2,@SupplierID,@CategoryID,@QuantityPerUnit,@UnitPrice,@UnitsInStock,@UnitsOnOrder,@ReorderLevel,@Discontinued);
SELECT [ProductID],[ProductName] as ProductName2,[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued]
FROM [dbo].[Products]
WHERE [ProductID] = SCOPE_IDENTITY();
此方法生成的結果
96 testvalue
八、批增加(使用選擇)
public static void DoInsertEntityParamBatch()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
// 設定要批處理的資料
List<AzProducts> azProductList = new List<AzProducts>{
new AzProducts { ProductName2 = "testvalue1" ,CategoryID=1,UnitPrice=123},
new AzProducts { ProductName2 = "testvalue2" ,CategoryID=1,UnitPrice=123},
new AzProducts { ProductName2 = "testvalue3" ,CategoryID=1,UnitPrice=123},
new AzProducts { ProductName2 = "testvalue4" ,CategoryID=1,UnitPrice=123 },
new AzProducts { ProductName2 = "testvalue5" ,CategoryID=1,UnitPrice=123},
new AzProducts { ProductName2 = "testvalue6" ,CategoryID=1,UnitPrice=123},
};
// 使用選擇增加
var resultinsert = repository
.Insert().ParamWith(c => c.ProductName2, c => c.UnitPrice, c => c.CategoryID);
Console.WriteLine(resultinsert.ParamSql());
Console.WriteLine();
// 通過 Dapper 批處理
dbConnection.Execute(resultinsert.ParamSql(), azProductList);
}
此方法生成的 SQL
INSERT [dbo].[Products]([ProductName],[UnitPrice],[CategoryID])
VALUES(@ProductName2,@UnitPrice,@CategoryID);
SELECT [ProductName] as ProductName2,[UnitPrice],[CategoryID],[ProductID]
FROM [dbo].[Products]
WHERE [ProductID] = SCOPE_IDENTITY();
九、更新
public static void DoUpdateEntityParam()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
// 構建更新語句
var resultUpdate = repository
.Update()
.ParamSet(p => p.ProductName2, p => p.CategoryID)
// Where 中使用下列格式語句,可生成帶 @ 的引數
.Where(p => p.ProductID == p.ProductID);
Console.WriteLine(resultUpdate.ParamSql());
Console.WriteLine();
// 需更新的資料
AzProducts products = new AzProducts() { ProductID = 84, ProductName2 = "testvalue100", CategoryID = 7 };
// 通過 Dapper 更新資料
int result = dbConnection.Execute(resultUpdate.ParamSql(), products);
Console.WriteLine($"{result}");
}
此方法生成的 SQL
UPDATE [dbo].[Products]
SET ProductName = @ProductName2, CategoryID = @CategoryID
WHERE (([dbo].[Products].[ProductID] = @ProductID));
十、刪除
public static void DoDeleteEntity(bool go = false)
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
// 要刪除的資料
AzProducts azProducts = new AzProducts { ProductName2 = "testvalue", ProductID = 81 };
// 構建刪除,使用例項構建時,如果不設定 Where 語句
// SqlRepoEx 會以關鍵詞來構建 Where 語句
var resultUpdate = repository.Delete().For(azProducts);
Console.WriteLine(resultUpdate.Sql());
Console.WriteLine();
// 通過 Dapper 刪除資料
int result = dbConnection.Execute(resultUpdate.Sql());
Console.WriteLine($"{result}");
}
此方法生成的 SQL
DELETE [dbo].[Products]
WHERE (([dbo].[Products].[ProductID] = @ProductID));
十一、使用事務
public static void DoDeleteTransaction()
{
// 建立資料倉儲
var repository = MsSqlRepoFactory.Create<AzProducts>();
// 構建刪除,如果不是例項構建,使用者必需自行指定刪除條件
// Where 中使用下列格式語句,可生成帶 @ 的引數
var resultUpdate = repository.Delete().Where(p => p.ProductID == p.ProductID);
// 要刪除的資料集
List<AzProducts> azProductList = new List<AzProducts>
{
new AzProducts{ProductID=92},
new AzProducts{ProductID=93},
new AzProducts{ProductID=94},
new AzProducts{ProductID=91},
};
Console.WriteLine(resultUpdate.Sql());
Console.WriteLine();
// 使用事務控制
using (var transaction = dbConnection.BeginTransaction())
{
// 通過 Dapper 刪除,同時指定了事務
dbConnection.Execute(resultUpdate.Sql(), azProductList, transaction: transaction);
// 僅為了演示,此處回滾事務,取消刪除
// 如果相要提交事務,請將此處改為 transaction.Commit() 可看到刪除效果
transaction.Rollback();
}
}
此方法生成的 SQL
DELETE [dbo].[Products]
WHERE (([dbo].[Products].[ProductID] = @ProductID));