SqlCommand

SqlCommand
2008-05-06 15:24
使用SqlCommand對象
執行動態SQL語句和存儲過程是應用程序所需的兩種最常見的數據庫活動。動態SQL語句是指從客戶端應用程序發送到數據庫服務器時由數據庫服務器讀取並執行的SQL語句。在數據庫接收這些SQL語句時,首先對它們進行解析以確保語法正確,然後數據庫引擎創建一個訪問計劃——主要確定處理該SQL語句的最佳方法——然後執行該語句。與經常用於執行SQL DML操作(如創建表)或數據訪問操作(執行ad hoc查詢)的動態SQL語句不同,存儲過程通常用於執行預先定義的查詢和數據庫更新操作。存儲過程形成了大多數數據庫應用程序的主幹。動態SQL語句和存儲過程之間的主要區別是,存儲過程一般是在執行應用程序之前創建的,並駐留在數據庫中。這使得存儲過程的性能遠遠超過了動態SQL語句,因爲解析SQL語句和創建數據訪問計劃的工作早已經被完成。值得注意的是,使用由SqlCommandBuilder類創建的動態SQL語句可以將ADO.NET DataSet中的數據變化傳回到數據庫中,或者可以使用存儲過程將它們寫回到數據庫。然而,您並不一定要使用DataSet和DataAdapter來更新數據庫。在不需要DataSet提供的數據綁定和定位功能的情況下,Command對象可以提供更簡單更有效的方法來更新數據庫。在接下來的部分,您將會看到如何使用SqlCommand對象來執行ad hoc查詢、如何執行SQL DDL語句爲目標數據庫構建一個表,以及兩個使用存儲過程的示例。第一個存儲過程示例將參數傳遞到一個存儲過程中,第二個示例執行一個提供返回值的存儲過程。
表6-3列出了SqlCommand對象和OleDbCommand對象支持的所有不同的SQL命令的執行方法。
表6-3 SqlCommand SQL語句執行方法
方    法
說    明
ExecuteNonQuery
該方法用於執行連接數據源上的SQL語句。它用於一些DDL語句、活動查詢(如Insert、Update和Delete操作),以及ad hoc查詢。該方法返回受影響的行數,但並不輸出所返回的參數或結果集
ExecuteReader
該方法用於執行數據源上的SQL Select語句。它返回一個快速只向前的結果集
ExecuteScalar
該方法用於執行一個返回單個標量值的存儲過程或SQL語句。它將結果集中的第一列的第一行返回到調用應用程序,並忽略其他所有返回值
ExecuteXMLReader
該方法用於執行返回數據源中某個XML數據流的FOR XML SELECT語句。ExecuteXMLReader命令只與SQL Server 2000及更高版本兼容
6.7.1 執行動態SQL語句
動態SQL爲使用數據庫提供了極爲靈活的機制。動態SQL允許您執行ad hoc查詢並返回活動查詢的結果,以及執行SQL DDL語句創建數據庫對象。下面的SQLCommandNonQuery子程序提供了一個示例示範瞭如何對ADO.NET SqlCommand對象使用動態SQL來檢查表是否存在,如果不存在,則有條件地創建一個表:
Private Sub SQLCommandNonQuery(cn As SqlConnection)
Dim sSQL As String = ""
Dim cmd As New SqlCommand(sSQL, cn)
Try
' First drop the table
sSQL = "IF EXISTS " _
& "(SELECT * FROM dbo.sysobjects WHERE id = " _
& "object_id(N’[Department]’) " _
& "AND OBJECTPROPERTY(id, N’IsUserTable’) = 1) " _
& "DROP TABLE [department]"
cmd.CommandText = sSQL
cmd.ExecuteNonQuery()
' Then create the table
sSQL = "CREATE TABLE Department " _
& "(DepartmentID Int NOT NULL, " _
& "DepartmentName Char(25), PRIMARY KEY(DepartmentID))"
cmd.CommandText = sSQL
cmd.ExecuteNonQuery()
Catch e As Exception
MsgBox(e.Message)
End Try
End Sub
在這個SQLCommandNonQuery子程序的第一部分,您可以看到,SQL Server連接對象被當作一個參數傳遞。並且使用sSQL變量包含動態SQL語句,實例化一個名爲cmd的SqlCommand對象實例。在該示例中,SqlCommand對象cmd的構造函數使用了兩個參數——第一個是包含要執行的SQL語句的字符串,第二個是提供目標數據庫服務器連接的SqlConnection對象。這裏的sSQL字符串最初爲空。接下來設置一個Try-Catch結構來執行SQL命令。Try-Catch中的第一個活動爲sSQL變量賦值了一個SQL語句,它檢查是否存在department表。在這個SQL語句中,您可以看到有一個SELECT語句查詢SQL Server的sysobjects表來確定是否存在一個名爲Department的User Table。如果發現Department表,則執行DROP TABLE語句從目標數據庫中刪除這個表。如果沒有發現Department表,則不採取進一步的行動。爲了真正執行SQL語句,則將sSQL變量中的值賦給cmd對象的CommandText特性,然後使用SqlCommand對象cmd的ExecuteNonQuery方法將該命令發送到SQL Server系統。ExecuteNonQuery方法用於執行一個不返回結果集或特定返回值的SQL語句。
在初次使用DROP TABLE SQL命令之後,按照相同的順序執行Create Table命令。首先爲sSQL變量賦值SQL CREATE TABLE語句,該語句創建了一個由兩個列組成的名爲Department的表。第一列是名爲DepartmentID的整型數據類型,它也是主鍵,第二列是名爲DepartmentName的25個字符的數據類型。接下來將sSQL變量中的值複製到cmd對象的CommandText特性中,並調用ExecuteNonQuery方法執行CREATE TABLE SQL語句。接下來成功執行ExecuteNonQuery方法,Department Table位於sDB變量先前確定的數據庫中。
如果Try代碼段中包含的任何操作發生錯誤,則執行Catch部分的代碼,並給出一個消息框,顯示異常情況的文本。
6.7.2 執行參數化的SQL語句
除了執行動態SQL語句之外,您還可以使用SqlCommand對象執行存儲過程和參數化的SQL語句。動態SQL和預定的SQL之間的主要區別是,在運行動態SQL語句之前必須對它進行解析並創建一個訪問計劃(類似於SQL Server等一些數據庫系統的處理方法非常靈活,而且它們也確實保存動態語句一段時間。然後在接下來執行該語句的時候使用已有的訪問計劃。雖然如此,這依賴於數據庫活動,而且使用動態SQL也不能保證該計劃立即可用)。您可以將預定的SQL語句當作存儲過程和動態SQL的混合。與存儲過程一樣,它們在運行時可以接受不同的參數值。與動態SQL一樣,它們在數據庫中並不穩定。在應用程序執行該SQL語句時將解析SQL語句並創建訪問計劃。然而,與動態SQL不同,在初次制定預定的SQL語句時,解析並創建訪問計劃的過程只執行一次。接下來執行的語句利用了已有的訪問計劃。該訪問計劃通常保留在過程緩存器中,直到該連接被終止。以下示例顯示瞭如何使用ADO.NET SqlCommand對象創建和執行預定的SQL語句:
Private Sub SQLCommandPreparedSQL(cn As SqlConnection)
' Set up the Command object's parameter types
Dim cmd As New SqlCommand("INSERT INTO department VALUES" & _
"(@DepartmentID, @DepartmentName)", cn)
Dim parmDepartmentID = _
New SqlParameter("@DepartmentID", SqlDbType.Int)
parmDepartmentID.Direction = ParameterDirection.Input
Dim parmDepartmentName = _
New SqlParameter("@DepartmentName", SqlDbType.Char, 25)
parmDepartmentName.Direction = ParameterDirection.Input
' Add the parameter objects to the cmd Parameter’s collection
cmd.Parameters.Add(parmDepartmentID)
cmd.Parameters.Add(parmDepartmentName)
Try
cmd.Prepare()
' Execute the prepared SQL statement to insert 10 rows
Dim i As Integer
For i = 0 To 10
parmDepartmentID.Value = i
parmDepartmentName.Value = "New Department " & CStr(i)
cmd.ExecuteNonQuery()
Next
Catch e As Exception
MsgBox(e.Message)
End Try
End Sub
您可以看到,CommandPrepareSQL子程序的頂部引入了一個名爲cn的SqlConnection對象,接下來創建了一個名爲cmd的新SqlCommand對象。在該示例中,構造函數使用了兩個參數。第一個參數用於爲cmd對象賦值一個SQL語句。它可以是一個SQL語句或存儲過程的名稱。這裏的SQL語句是向Department表中添加兩列值的INSERT語句。
注意
Department表是在本章前面部分創建的。
該示例中需要注意的要點是SQL語句中使用的參數標記的格式。參數標記用於指示預定SQL語句中可替換的字符。在運行時,將使用SqlCommand對象的Parameters集合中提供的實際值來替換這些參數。與使用問號(?)指示可替換參數的ADO不同,SqlCommand對象要求所有參數標記以@符號開頭。該示例顯示了兩個參數標記:@DepartmentID和@DepartmentName。SqlCommand構造函數的第二個參數將SqlCommand對象cmd與前面傳入的SqlConnection對象cn結合在一起。
接下來創建了兩個SqlParameter對象。第一個參數對象parmDepartmentID用於提供第一個參數標記(@DepartmentID)的值。同樣,第二個參數對象parmDepartmentName提供第二個可替換參數(@DepartmentName)使用的值。該子程序中使用的代碼示例顯示了要被傳遞到SqlParameter構造函數中的3個參數。第一個參數提供了參數名。這裏需要確保提供給SqlParameter對象中構造函數的名稱與預定SQL語句的參數標記中使用的名稱匹配。第二個參數被傳遞到SqlParameter構造函數的重載版本中,它指定了該參數的數據類型。
這裏的Direction特性被設置爲使用ParameterDirection.Input枚舉類型進行輸入。表6-4列出了SqlParameter Direction特性可用的枚舉類型。
表6-4 SqlParameterDirection枚舉
枚    舉
說    明
ParameterDirection.Input
該參數爲輸入參數
ParameterDirection.InputOutput
該參數可以爲輸入參數也可以爲輸出參數
ParameterDirection.Output
該參數爲輸出參數
ParameterDirection.ReturnValue
該參數表示一個返回值
在創建SqlParameter對象之後,接下來將它們添加到SqlCommand對象的Parameters集合中。您可以看到,前面清單中使用SqlCommand對象的Parameters集合的Add方法將parmDepartmentID和parmDepartmentName SqlParameter對象添加到SqlCommand對象cmd中。SqlParameter對象的添加順序並不重要。接下來,在Try-Catch代碼段中使用Prepare語句指定該語句。注意,Prepare方法是在描述了所有參數特性之後才執行的。
注意
使用Prepare操作可以爲參數化查詢提供重要的性能優勢,因爲它指示SQL Server使用sp_prepare語句,因此確保該語句保留在Procedure緩存中,直到關閉該語句句柄。
接下來使用For-Next循環向新建的Department表中添加10行。在For-Next循環中,每個參數對象的Value特性被賦值爲一個新的數據值。爲了簡化起見,parmDepartmentID參數被賦值爲變量i中包含的循環計數器的值,而parmDepartmentName參數被賦值爲一個包含“New Department”和循環計數器的當前值字符串。最後,SqlCommand對象的ExecuteNonQuery方法用於執行該SQL語句。在本示例中使用了ExecuteNonQuery,因爲該示例使用了不返回任何值的SQL活動查詢。從SQL Server的角度看,運行ExecuteNonQuery方法會導致該服務器使用sp_execute命令真正執行插入操作。
注意
如果需要傳遞一個空值參數,則需要設置該參數爲DBNull.Value值。
如果在任何操作過程中發生了錯誤,則執行Catch部分的代碼,並給出一個消息框,顯示異常情況的文本。
6.7.3 執行帶返回值的存儲過程
存儲過程是大多數數據庫應用程序的核心。除了它們的性能優勢以外,存儲過程作爲一種機制還可以對它提供的預定界面的數據訪問進行限制。類似於預定的SQL語句,由於存儲過程是在使用之前進行編譯,因此它能獲得更強的性能。這允許數據庫放棄通常所需的解析步驟,跳過創建訪問計劃的需求。存儲過程是大多數數據庫應用程序的實際工作設備,它們幾乎總是用於數據庫的插入、更新和刪除操作,並檢索單個值和結果集。在接下來的示例中,您將會看到如何使用SqlCommand對象執行SQL Server存儲過程。在第一個示例之後,您將會看到如何執行存儲過程來接受一個輸入參數並返回一個標量值。
以下清單顯示了創建CostDiff存儲過程(將被添加到AdventureWorks數據庫示例中)所需的T-SQL源代碼。通過使用SQL Server Management Studio執行該代碼,可以創建這個存儲過程:
CREATE PROCEDURE CostDiff
@ProductID int
AS
DECLARE @CostDiff money
SELECT CostDiff = (ListPrice - StandardCost)
FROM Production.Product WHERE ProductID = @ProductID
RETURN @CostDiff
在這個清單中,您可以看到CostDiff存儲過程接受了一個輸入參數。該參數是一個用於標識ProductID的Integer值。CostDiff存儲過程返回AdventureWorks數據庫的Production.Product表中ProductID的成本差額。成本差額是通過檢索ListPrice數並從StandardCost列的值中減去該值計算得到的。然後將這個值賦給@CostDiff變量,該變量由存儲過程作爲一個標量值返回。在AdventureWorks數據庫中創建了示例存儲過程之後,您的ADO.NET應用程序可以對它進行調用。以下示例顯示瞭如何在VB.NET中使用SqlCommand類來執行CostDiff存儲過程並檢索它返回的標量值:
Private Sub SQLCommandSPScalar(cn As SqlConnection)
' Create the command object and set the SQL statement
Dim cmd As New SqlCommand("CostDiff", cn)
cmd.CommandType = CommandType.StoredProcedure
' Create the parameter
cmd.Parameters.Add("@ProductID", SqlDbType.Int)
cmd.Parameters("@ProductID").Direction = _
ParameterDirection.Input
cmd.Parameters("@ProductID").Value = 1
Try
Dim nCostDiff As Decimal
nCostDiff = cmd.ExecuteScalar()
' Put to textbox on displayed form
txtMid.Text = nCostDiff
Catch e As Exception
MsgBox(e.Message)
End Try
End Sub
您可以看到,該程序的開始部分引入了SqlConnection對象cn,接下來創建了名爲cmd的SqlCommand對象。在該示例中,SqlCommand對象的構造函數使用了兩個參數。第一個參數是接受將要執行的命令的字符串。它可以是SQL語句或存儲過程的名稱。您可以看到該示例中使用了CostDiff存儲過程的名稱。第二個參數用於SqlConnection對象(用於連接到目標數據庫)的名稱。在創建了SqlCommand對象cmd之後,將它的CommandType特性設置爲CommandType.StoredProcedure,表示將要執行一個存儲過程。這個CommandType特性可以接受表6-5中所示的任何值。
表6-5 CommandType值
CommandType值
說    明
CommandType.StoredProcedure
該命令是一個存儲過程
CommandType.TableDirect
該命令是一個數據庫表的名稱
CommandType.Text
該命令是一個SQL語句
在將SqlCommand對象的CommandType特性設置爲CommandType.StoredProcedure之後,使用SqlParameter對象向創建的CostDiff存儲過程提供輸入值。您可以使用SqlParameter類的構造函數或執行SqlCommand對象的Parameters集合的Add方法來創建SqlParameter對象。在該示例中,該參數是使用SqlCommand對象的Parameters集合的Add方法創建的。提供給Add方法的第一個參數是包含該參數名稱的字符串,在這裏是“@ProductID”。此外還要注意,SqlParameter對象使用的可替換參數必須以@符號開始。第二個參數使用了SqlDbType.Int枚舉,表示該參數包含一個Integer值。接下來的代碼行將Direction特性設置爲值ParameterDirection.Input,表示這是個輸入參數。最後,將SqlParameter對象的Value特性設置爲1,並將它傳遞到CostDiff存儲過程。
接下來的代碼部分建立了一個執行CostDiff存儲過程的Try-Catch代碼段。在這個Try-Catch代碼段中要注意的重點是,SqlCommand對象cmd的ExecuteScalar方法用於執行CostDiff存儲過程並將返回值賦給nCostDiff變量。然後將nCostDiff變量的內容賦給一個名爲txtMid的文本框,該文本框是在該項目的Windows窗體上定義的。與前面的示例一樣,如果存儲過程失敗,則向終端用戶彈出一個消息框,顯示錯誤文本。
發佈了3 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章