于磊
摘 要:在基于C#的WinForm+SQL數據庫應用開發中,存在著大量數據庫操作,直接使用命令字符串進行操作的常規方式存在執行速度低、增加網絡通信量、修改困難等問題。改善上述問題的有效方法是利用SQL Server提供的存儲過程進行數據庫操作。在實際開發中應用存儲過程,采用不同方法進行對比測試,結果表明,在開發中合理應用存儲過程能有效地將應用與數據操作分離,提高運行效率,提高數據庫訪問的安全性并增加靈活性。
關鍵詞:C#;WinForm;SQL;存儲過程
DOI:10.11907/rjdk.172524
中圖分類號:TP319
文獻標識碼:A 文章編號:1672-7800(2018)004-0178-02
Abstract:In C# based WinForm+SQL application development, there is a large number of database operations. In general, we use command strings to perform database operations, but this method will reduce execution speed, increase network traffic and cause difficulty of modification. In order to improve the above problems, one efficient method is proposed to use the stored procedure of SQL Server to complete database operations. Through the use of stored procedure and the different methods in the development, the results show that applying stored procedure rationally in developmentrational employment of the stored procedure in develoment can effectively separate application implementation from data operation, improve operation efficiency and database access security and enhance flexibility.
Key Words:C#; WinForm; SQL; Stored Procedure
0 引言
在基于C#的WinForm+SQL應用開發中,應用程序與數據庫之間存在大量數據操作,這些操作通常通過ADO.NET實現。ADO.NET是.NET框架中的一個組件庫,在技術上高于現有的API。ADO.NET分為數據提供程序和數據集兩個部分,實現了數據訪問和數據操作的分離。其數據操作一般過程為:創建連接對象,打開與數據庫的連接,通過Command類對象選擇數據后把它們放到記錄集中,接著處理并在服務器上更新這些數據,最后關閉它們。在該過程中,ADO.NET所提供的基礎方式是將實現數據庫操作的T-SQL語句以字符串的形式直接編寫在C#代碼中,這種方式難以滿足性能優化、安全性和易維護的開發要求。除了進行SQL語句的性能調優,借助SQL Server的存儲過程完成數據庫操作是解決上述問題的重要方法。
1 SqlCommand對象
在ADO.NET中,對應于SQL Server提供程序的SqlCommand類對象負責執行對數據庫進行操作的各種命令,包括SELECT、INSERT、UPDATE、DELETE等,一般過程為:①創建SqlCommand類對象;②將數據庫操作對應的SQL語句指定給該對象的CommandText屬性;③將該對象綁定到一個打開的數據庫連接對象;④調用該對象的相應執行方法或將該對象綁定到DataAdapter完成數據操作。
例如:在基于C#開發的成人高等教育畢業生審核系統中,為了將成教畢業生申報數據與學信網的學生學籍數據進行一致性比對,對畢業生申報數據表與學信網的在校生學籍數據表進行了一個左外連接操作,代碼如下:
DataTable checkTable=new DataTable();
SqlCommand checkConsistencyCmd=new SqlCommand(@"SELECT * FROM (SELECT ksh,xh,cm,xb,csrq,sfzh,zydm,zymc,cc,xxxs,xz,rxrq,yjbyrq,bysxjcf,xjjyt,jc FROM bmdr WHERE xjzt='在校') AS t1 LEFT OUTER JOIN(SELECT ksh,xh,xm,xb,csrq,sfzh,zydm,zymc,cc,xxxs,xz FROM zxs)as t2 ON t1.ksh=t2.ksh",adultEduConn);
SqlDataAdapter checkAda=new SqlDataAdapter(checkConsistencyCmd);
try
{
checkAda.Fill(checkTable);
}
catch(Exception ex){……}
該方式是ADO.NET提供的操作數據庫基本方式,在存在大量T-SQL語句需要逐條執行的情況下至少存在以下問題:語句的逐條編譯執行會降低執行速度,大量T-SQL語句的傳輸會占用一定的網絡通信量,由于T-SQL語句是以文本的方式嵌入C#代碼中的,其修改完全依賴于對應用程序的修改。
2 存儲過程及應用
(1)調用存儲過程進行數據庫操作。 ADO.NET的命令對象可以調用存儲過程完成SQL數據庫的操作。存儲過程建立在SQL服務器上,是一組預先編譯好的T-SQL語句,由用戶通過指定存儲過程的名字執行。
存儲過程調用與上述通過命令字符串的方式進行數據庫操作在使用過程上的差異在于,前者需要事先在SQL服務器上創建存儲過程,然后在SqlCommand類的對象上綁定存儲過程并將對象的CommandType屬性指派為“StoreProcedure”。
例如:由于成人教育的特殊性,成人在校生可能存在多個學籍,為了統計出每個畢業生是否存在重復學籍,在SQL服務器上編寫如下存儲過程:
create procedure chkXJCF with encryption as
begin
UPDATE bmdr SET bysxjcf=t2.d FROM (SELECT ksh AS c,t1.b AS d FROM bmdr,(SELECT sfzh AS a,count(sfzh) AS b FROM bmdr GROUP BY sfzh) AS t1 WHERE bmdr.sfzh=t1.a) AS t2 WHERE bmdr.ksh=t2.c
UPDATE bmdr SET zxsxjcf=t2.d FROM (SELECT ksh AS c,t1.b AS d FROM bmdr,(SELECT sfzh AS a,count(sfzh) AS b FROM zxs GROUP BY sfzh) AS t1 WHERE bmdr.sfzh=t1.a) AS t2 WHERE bmdr.ksh=t2.c
end
為了調用該存儲過程,在C#程序中使用如下代碼:
SqlCommand chkCMD=new SqlCommand(@"chkXJCF",adultEduConn);
chkCMD.CommandType=CommandType.StoreProcedure;
try{
aduleEduConn.Open();
chkCMD.ExecuteNonQuery();
}
catch(Exception ex){……}
與通過命令字符串方式進行數據庫操作相比,存儲過程調用好處有:存儲過程在第一次調用后就駐留在內存中,不需要二次編譯和優化,提升了執行性能,且由于存儲過程通過指定的名字執行,降低了網絡通信量;存儲過程存在于SQL服務器上,完全獨立于應用程序,即使出現修改需求也不影響應用程序;存儲過程可以通過授權提供更高的安全性。
(2)利用存儲過程實現參數化查詢。 存儲過程可以攜帶參數,并通過指定參數的方向完成應用程序中的參數化查詢。由于參數是類型化的替代占位符,而非未經檢查的純文本,因此可以有效防范類似于SQL注入之類的攻擊,提高安全性。除了在SQL服務器上正確編寫帶參數的存儲過程外,還需要為SqlCommand對象增加參數,以完成參數的傳遞。
例如:為了將往屆未通過審核的成教畢業生數據追加到本屆待審核數據中,需要通過姓名查找未通過審核畢業生數據表并排除該姓名在本屆待審核數據中的存在,存儲過程就需要用學生的姓名作為一個輸入參數完成查詢。建立存儲過程代碼如下:
create procedure joinwith_xm (@para char(40)) with encryption as
begin
select RTRIM(ksh) AS ksh,RTRIM(xh) AS xh,RTRIM(xm) AS xm,RTRIM(xb) AS xb, sfzh, RTRIM(zydm) AS zydm, RTRIM(zymc) AS zymc, RTRIM(cc) AS cc, RTRIM(xxxs) AS xxxs,RTRIM(xz) AS xz from WBY where xm=@para and ksh not in (select ksh from bmdr where xm=@para)
……
end
為了完成該存儲過程的調用,在使用SqlCommand對象時,除了對象的CommandType屬性指派為“StoreProcedure”外,還應創建相關參數,并將它們附加到SqlCommand對象上:
SqlCommand joinCmd=new SqlCommand("joinwith_xm",adultEduConn);
joinCmd.CommandType=CommandType.StoreProcedure;
joinCmd.Parameters.AddWithValue("@para",searchPanel.GetXM);
SqlDataAdapter joinAda=new SqlDataAdapter(joinCmd);
try{
joinAda.Fill(joinTable);
}
catch(Exception ex){……}
3 結語
在基于C#的WinForm+SQL數據庫應用開發中合理使用存儲過程,能有效將應用實現與數據操作分離,提高運行效率,提高數據庫訪問的安全性并增強系統的靈活性。
參考文獻:
[1] WILDERMUTH S. ADO.NET應用程序開發(MCTS教程)[M].北京:清華大學出版社,2010.
[2] NAGEL C. C#高級編程 [M].第9版.北京:清華大學出版社,2014.
[3] BEN-GAN I. SQL Server 2012 T-SQL基礎教程[M].北京:人民郵電出版社,2013.
[4] HAMILTON B. ADO.NET3.5經典實例[M].第2版.北京:機械出版社,2009.
[5] DEITEL P J, DEITEL H M. C# 2008程序員教程[M].第3版.北京:電子工業出版社,2009.
[6] CLARKE J. SQL注入攻擊與防御[M].北京:清華大學出版社,2013.
[7] FRITCHEY G, DAM S. SQL Server 2008查詢性能優化[M].北京:人民郵電出版社,2010.
[8] JORGENSEN A. SQL Server 2012管理高級教程[M].第2版.北京:清華大學出版社,2011.
[9] MICHAELIS M. C#本質論[M].第2版.北京:人民郵電出版社,2009.
[10] BROWN E. Windows Forms編程實戰[M].北京:機械工業出版社,2008.
(責任編輯:杜能鋼)