国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > SQL Server > 正文

CPQuery 解決拼接SQL的新方法

2024-08-31 00:44:48
字體:
來源:轉載
供稿:網友

我一直都不喜歡在訪問數據庫時采用拼接SQL的方法,原因有以下幾點:
1. 不安全:有被SQL注入的風險。
2. 可能會影響性能:每條SQL語句都需要數據庫引擎執行[語句分析]之類的開銷。
3. 影響代碼的可維護性:SQL語句與C#混在一起,想修改SQL就得重新編譯程序,而且二種代碼混在一起,可讀性也不好。
所以我通常會選擇【參數化SQL】的方法去實現數據庫的訪問過程,而且會將SQL語句與項目代碼(C#)分離開。

不過,有些人可能會說:我的業務邏輯很復雜,Where中的過慮條件不可能事先確定,因此不拼接SQL還不行。

看到這些缺點,ORM用戶可能會認為:使用ORM工具就是終極的解決方案。
是的,的確ORM可以解決這些問題。
但是,解決方案并非只有ORM一種,還有些人就是喜歡寫SQL呢。
所以,這篇博客不是寫給ORM用戶的,而是寫給所有喜歡寫SQL語句的朋友。

CPQuery是什么?
看到博客的標題,你會不會想:CPQuery是什么?

下面是我的回答:
1. CPQuery 是一個縮寫:Concat Parameterized Query
2. CPQuery 可以讓你繼續使用熟悉的拼接方式來寫參數化的SQL
3. CPQuery 是我設計的一種解決方案,它可以解決拼接SQL的前二個缺點。
4. CPQuery 也是這個解決方案中核心類型的名稱。

希望大家能記住CPQuery這個名字。

CPQuery適合哪些人使用?
答:適合于喜歡手寫SQL代碼的人,尤其是當需要寫動態查詢時。

參數化的SQL語句
對于需要動態查詢的場景,我認為:拼接SQL或許是必需的,但是,你不要將數值也拼接到SQL語句中嘛,或者說,你應該拼接參數化的SQL來解決你遇到的問題。

說到【拼接參數化SQL】,我想解釋一下這個東西了。
這個方法的實現方式是:拼接SQL語句時,不要把參數值拼接到SQL語句中,在SQL語句中使用占位符參數,具體的參數值通過ADO.NET的command.Parameters.Add()傳入。現在流行的ORM工具應該都會采用這個方法。

我認為參數化的SQL語句可以解決本文開頭所說的那些問題,尤其是前二個。對于代碼的維護問題,我的觀點是:如果你硬是將SQL與C#混在一起,那么參數化的SQL語句也是沒有辦法的。如果想解決這個問題,你需要將SQL語句與項目代碼分離,然后可以選擇以配置文件或者存儲過程做為保存那些SLQ語句的容器。

所以,參數化的SQL并不是萬能的,代碼的可維護性與技術的選擇無關,與架構的設計有關。任何優秀的技術都可能寫出難以維護的代碼來,這就是我的觀點。

改造現有的拼接語句
還是說動態查詢,假設我有這樣一個查詢界面:

顯然,在設計程序時,不可能知道用戶會輸入什么樣的過濾條件。
因此,喜歡手寫SQL的人們通常會這樣寫查詢:

復制代碼 代碼如下:


var query = "select ProductID, ProductName from Products where (1=1) ";
if( p.ProductID > 0 )
query = query + " and ProductID = " + p.ProductID.ToString();
if( string.IsNullOrEmpty(p.ProductName) == false )
query = query + " and ProductName like '" + p.ProductName + "'";
if( p.CategoryID > 0 )
query = query + " and CategoryID = " + p.CategoryID.ToString();
if( string.IsNullOrEmpty(p.Unit) == false )
query = query + " and Unit = '" + p.Unit + "'";
if( p.UnitPrice > 0 )
query = query + " and UnitPrice >= " + p.UnitPrice.ToString();
if( p.Quantity > 0 )
query = query + " and Quantity >= " + p.Quantity.ToString();


如果使用這種方式,本文開頭所說的前二個缺點肯定是存在的。
我想很多人應該是知道參數化查詢的,最終放棄或許有以下2個原因:
1. 這種拼接SQL語句的方式很簡單,非常容易實現。
2. 便于包裝自己的API,參數只需要一個(萬能的)字符串!
如果你認為這2個原因很難解決的話,那我今天就給你 “一種改動極小卻可以解決上面二個缺點”的解決方案,改造后的代碼如下:

復制代碼 代碼如下:


var query = "select ProductID, ProductName from Products where (1=1) ".AsCPQuery(true);
if( p.ProductID > 0 )
query = query + " and ProductID = " + p.ProductID.ToString();
if( string.IsNullOrEmpty(p.ProductName) == false )
query = query + " and ProductName like '" + p.ProductName + "'";
if( p.CategoryID > 0 )
query = query + " and CategoryID = " + p.CategoryID.ToString();
if( string.IsNullOrEmpty(p.Unit) == false )
query = query + " and Unit = '" + p.Unit + "'";
if( p.UnitPrice > 0 )
query = query + " and UnitPrice >= " + p.UnitPrice.ToString();
if( p.Quantity > 0 )
query = query + " and Quantity >= " + p.Quantity.ToString();


你看到差別了嗎?
差別在于第一行代碼,后面調用了一個擴展方法:AsCPQuery(true) ,這個方法的實現代碼我后面再說。
這個示例的主要關鍵代碼如下:

復制代碼 代碼如下:

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 永州市| 陆良县| 阿拉善右旗| 定边县| 吴忠市| 老河口市| 巴楚县| 平南县| 宜昌市| 宁城县| 京山县| 宣威市| 黄龙县| 修文县| 河北区| 彰化市| 阿克| 新绛县| 腾冲县| 扬中市| 独山县| 崇义县| 黄龙县| 宁海县| 元氏县| 遂昌县| 南康市| 安溪县| 黄梅县| 伊吾县| 库尔勒市| 阜新市| 葵青区| 尼木县| 安溪县| 二连浩特市| 长寿区| 安西县| 宁国市| 东安县| 新乡县|