從存儲過程返回值 以上示例有一個不足之處。Northwind Customers 表使用數字字母形式的主鍵,并且必須由插入數據的應用程序生成。也就是說,如果使用以上程序插入新記錄,則必須為 CustomerID 自行創建由五個字符組成的值。
在真實軟件中,為新記錄自動生成主鍵更為常見。主鍵通常是按順序分配的長整數。
為新記錄設置主鍵有兩種基本技術。應用程序可調用生成下一個可用 ID 的存儲過程,然后將此 ID 直接放到 DataSet 的新行中。或者,用于插入記錄的存儲過程可以為記錄派生新 ID,然后將其作為返回值傳遞回應用程序。
第一種技術需要一點額外的邏輯來獲取新 ID 并將其放到新記錄的相應位置。使用存儲過程執行插入操作與以上示例類似。
但第二種技術要求在存儲過程中使用一種新型參數。到目前為止我們見到的所有參數都是默認類型,即輸入參數。實際上參數分四種類型:
Input 此參數只用于將信息從應用程序傳輸到存儲過程。 InputOutput 此參數可將信息從應用程序傳輸到存儲過程,并將信息從存儲過程傳輸回應用程序。 Output 此參數只用于將信息從存儲過程傳輸回應用程序。 ReturnValue 此參數表示存儲過程的返回值。SQL Server 的存儲過程參數列表中不顯示該參數。它只與存儲過程的 RETURN 語句中的值相關聯。
存儲過程為主鍵生成新值后,通常使用存儲過程中的 RETURN 語句返回該值,因此用來訪問該值的參數類型是 ReturnValue 參數。
ReturnValue 參數與其他類型的參數有一個重要的區別。通常,在 ADO.NET 中為 Command 對象配置的參數的順序并不重要。參數名稱只用來與存儲過程中相應的參數相匹配。但是,對于 ReturnValue 參數,它必須是列表中的第一個參數。
也就是說,為 Command 對象配置 ReturnValue 參數時,必須首先在代碼中配置該參數,這樣它才能獲取集合中的第一個數字索引。如果先配置任何其他參數,ReturnValue 參數將不能正常工作。
為了說明帶返回值的存儲過程的用法,我們編寫一個在 Northwind Products 表中插入記錄的示例。此表被設置為使用 Identity 列自動創建新產品 ID。遺憾的是,Northwind 示例數據庫不包含執行所需操作的存儲過程,所以在完成示例其余部分之前,我們需要向數據庫插入一個這樣的存儲過程。
轉到 Visual Studio .NET 中的 Server Explorer(服務器資源管理器)。打開 SQL Server 的節點,打開 SQL Server 實例的節點,然后打開 Northwind 數據庫的節點。
右鍵單擊 Stored Procedures(存儲過程)節點,選擇 New Stored Procedure(新建存儲過程)。在出現的編輯窗口中,用以下文本替換其中的所有文本:
ALTER PROCEDURE dbo.MSDNInsertProduct ( @ProductName nvarchar(40), @SupplierID int, @CategoryID int, @QuantityPerUnit nvarchar(20), @UnitPrice money, @UnitsInStock smallint, @UnitsOnOrder smallint, @ReorderLevel smallint, @Discontinued bit ) AS declare @ProductID int
SET NOCOUNT OFF; INSERT INTO Products(ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued) VALUES (@ProductName, @SupplierID, @CategoryID, @QuantityPerUnit, @UnitPrice, @UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued); SELECT @ProductID = @@IDENTITY
RETURN @ProductID
現在關閉編輯窗口,當系統詢問您是否要保存更改時,單擊 Yes(是)。現在存儲過程就已保存到數據庫中,并被命名為 MSDNInsertProduct。
現在便可以編寫代碼來使用此存儲過程。新建 Windows 應用程序,在空白 Form1 上,放置錨定到所有四個邊的 DataGrid,還需添加名為 btnFill 和 btnInsertProduct 的兩個按鈕。將 btnFill 的 Text 屬性設置為 Fill,將 btnInsertProduct 的 Text 屬性設置為 Insert Product。
在 btnFill 的 Click 事件中,放置以下代碼:
Dim sConnectionString As String = _ "server=localhost;uid=sa;pwd=;database=Northwind" Dim sSQL As String = "SELECT * FROM Products" Dim daGetProducts As New SqlDataAdapter(sSQL, sConnectionString) Dim dsProducts As New DataSet() daGetProducts.Fill(dsProducts, "Products") DataGrid1.DataSource = dsProducts
它與本文前面所講的代碼大致相同,所以我們不再贅述。不要忘記必要時更改連接字符串,并在項目代碼的頂部為 SQLClient 命名空間放置 Imports 語句。然后在 btnInsertProduct 的 Click 事件中放置以下代碼:
Dim sConnectionString As String = _ "server=localhost;uid=sa;pwd=;database=Northwind" Dim cnNorthwind As New SqlConnection(sConnectionString) Dim cmdInsertProduct As New SqlCommand("MSDNInsertProduct", cnNorthwind) cmdInsertProduct.CommandType = CommandType.StoredProcedure ' 為存儲過程設置參數 cmdInsertProduct.Parameters.Add(New SqlParameter("@RETURN_VALUE", SqlDbType.Int, 4, "ProductID")) cmdInsertProduct.Parameters("@RETURN_VALUE").Direction = ParameterDirection.ReturnValue
cmdInsertProduct.Parameters.Add(New SqlParameter("@ProductName", _ SqlDbType.NVarChar, 40, "ProductName")) cmdInsertProduct.Parameters.Add(New SqlParameter("@SupplierID", _ SqlDbType.Int, 4, "SupplierID")) cmdInsertProduct.Parameters.Add(New SqlParameter("@CategoryID", _ SqlDbType.Int, 4, "CategoryID")) cmdInsertProduct.Parameters.Add(New SqlParameter("@QuantityPerUnit", _ SqlDbType.NVarChar, 20, "QuantityPerUnit")) cmdInsertProduct.Parameters.Add(New SqlParameter("@UnitPrice", _ SqlDbType.Money, 8, "UnitPrice")) cmdInsertProduct.Parameters.Add(New SqlParameter("@UnitsInStock", _ SqlDbType.SmallInt, 2, "UnitsInStock")) cmdInsertProduct.Parameters.Add(New SqlParameter("@UnitsOnOrder", _ SqlDbType.SmallInt, 2, "UnitsOnOrder")) cmdInsertProduct.Parameters.Add(New SqlParameter("@ReorderLevel", _ SqlDbType.SmallInt, 2, "ReorderLevel")) cmdInsertProduct.Parameters.Add(New SqlParameter("@Discontinued", _ SqlDbType.Bit, 1, "Discontinued"))
Dim daInsertProduct As New SqlDataAdapter() daInsertProduct.InsertCommand = cmdInsertProduct Dim dsProducts As DataSet = CType(DataGrid1.DataSource, DataSet)
Dim drNewProduct As DataRow drNewProduct = dsProducts.Tables("Products").NewRow drNewProduct.Item("ProductName") = "Billy's Sesame Oil" drNewProduct.Item("SupplierID") = 4 drNewProduct.Item("CategoryID") = 7 drNewProduct.Item("QuantityPerUnit") = "6 10oz bottles" drNewProduct.Item("UnitPrice") = 69 drNewProduct.Item("UnitsInStock") = 12 drNewProduct.Item("UnitsOnOrder") = 0 drNewProduct.Item("ReorderLevel") = 6 drNewProduct.Item("Discontinued") = False dsProducts.Tables("Products").Rows.Add(drNewProduct)
daInsertProduct.Update(dsProducts.Tables("Products"))
MsgBox(drNewProduct.Item("ProductID"))
此代碼與如上所示的代碼類似,只是為返回值配置參數的代碼行不同。請注意,它是第一個參數,并被設置為將返回值放回到 ProductID 字段中。
用于向數據集中插入新行的代碼是標準 ADO.NET 代碼,所以我們就不再贅述。它為產品記錄創建一行新的適當結構(使用產品 DataTable 的 NewRow 方法),然后將數據放入行中,最后向產品 DataTable 的 Rows 集合中添加行。
現在運行程序進行測試。單擊 Fill 按鈕,但不對網格中的數據進行任何更改。然后按 Insert Product 按鈕。將插入 Billy's Sesame Oil 的新產品記錄,并且出現的消息框會通知您為其返回的 ProductID。還可以打開網格中的 Products 表,滾動到底部,并看到已添加了新行。
使用 Server Explorer(服務器資源管理器)編寫參數代碼 以上代碼編寫起來既冗長又繁瑣。但是,DataAdapter Configuration Wizard(數據適配器配置向導)提示可以使用 Visual Studio 為我們編寫此代碼。DataAdapter Configuration Wizard(數據適配器配置向導)為完整配置所需的四個存儲過程(分別是 Select、Update、Insert 和 Delete)生成了代碼。假設您象以上示例一樣只需要一個存儲過程的代碼,可以將其截短。要獲得只與一個存儲過程通信的預先編寫好的代碼,只需展開 Server Explorer(服務器資源管理器)以顯示需要訪問的存儲過程,然后將該存儲過程拖到設計界面上。將看到為該存儲過程創建的 DataAdapter 和 Command 對象,代碼的設計器部分包含為該存儲過程配置參數所需的所有代碼。可以按原樣使用該代碼,也可以根據需要復制并調整后使用。
小結 本文中的示例仍是演示軟件,但至少足以向您說明如何訪問存儲過程,以便您開始編寫自己的真實軟件。當然,您需要了解要訪問的存儲過程,并且可能需要向數據庫管理員 (DBA) 或其他組員咨詢以獲取該信息。
對于復雜系統,存儲過程有許多優勢。希望您在本文中學到了足夠的知識,可以不必擔心如何開始使用它們。第一次嘗試編寫代碼時,您可能希望使用 DataAdapter Wizard(DataAdapter 向導)或 Server Explorer(服務器資源管理器)。但如果您能在必要時自行編寫訪問代碼,則可以更有效地使用存儲過程。
|