摘要:Billy Hollis 解釋了在復雜系統中使用存儲過程的好處,使存儲過程超出了演示軟件的范疇,並提供了有關如何訪問存儲過程並在您自己的應用程序中開始使用這些存儲過程的實用示例。
我們作者通常將軟件分為兩類 - 真實軟件和演示軟件。真實軟件是在真實環境中使用的軟件。演示軟件用於闡釋編程概念。
您在文章和書籍中看到的大部分代碼都是演示軟件。它必須比真實軟件簡單,否則讀者將為那些與闡釋的概念無關的細節而費神。但有時演示軟件又過於極端。追求簡單會忽略開發人員編寫真實軟件所需的細節。
最近我在數據訪問方面就曾遇到這樣一個問題。實際上,我見過的每個數據訪問示例都使用 SQL 語句從關系數據庫(例如,Microsoft SQL Server™)中讀取或向其中寫入。然而,在真實環境中,除了對有限的小型系統適用以外,這是很不可取的編程方法。結構合理的 n 層應用程序使用存儲過程代替 SQL 語句進行數據訪問。
存儲過程在概念上類似於程序中的函數。它們獲取輸入參數,以黑盒模式運行並返回相應信息。與函數不同的是,存儲過程由數據庫引擎執行,而不是在程序中執行。也就是說,將信息輸入到存儲過程或從中輸出信息都必須通過與數據庫交互的技術來完成。在 Microsoft Visual Basic® 6.0 中,該技術就是傳統的 ADO。在 Visual Basic .NET 中,我們可以使用 ADO.Net 完成該任務。
對於許多編程任務而言,Visual Basic .NET 使得通過存儲過程訪問數據比使用 Visual Basic 6.0 容易得多。其中有一些用來幫助該過程的向導,一旦您學會如何避免一些錯誤之後,即使使用 ADO.Net 從頭編寫這些邏輯也並不復雜。
本文介紹了一些在 ADO.Net 中使用存儲過程的基本技巧,並從只讀操作開始,一直到如何使用存儲過程進行數據插入、刪除和更新。
您無需精通存儲過程的編寫也可從本文受益。許多大型編程小組的開發人員需要使用他人編寫的存儲過程。我們的示例之一需要將存儲過程插入到示例數據庫中,但我們將逐步介紹這個任務。
ADO.Net 簡介
本文假設您已經了解了 ADO.NET 的基礎知識。如果您在工作中從未使用過 ADO.NET 中的 DataAdapter、DataSet 和 Command 對象,則應閱讀一些介紹 ADO.NET 的文章,包括 Rocky 為本專欄撰寫的名為 ADO.Net 與您一文。
簡而言之,DataSet 在 ADO.Net 中用作數據容器,並在與數據庫斷開連接時使用。DataSet 包含一個或多個 DataTable,每個 DataTable 都包含行集合。對於那些熟悉傳統 ADO 環境的用戶來說,DataTable 可被看作是斷開連接的 Recordset。
DataAdapter 在連接到數據庫時工作。單個 DataAdapter 的作用是使用數據庫中的數據填充某個 DataTable,或將 DataTable 中的更改寫回到數據庫,或者二者兼而有之。
DataAdapter 要求 Command 對象執行各種數據庫操作。Command 對象存放 SQL 語句或指定數據訪問實現方法的存儲過程名稱。每個 DataAdapter 有四個屬性,指定用於四種數據訪問類型之一的命令對象。
SelectCommand:此 Command 對象用於從數據庫中選擇數據。
UpdateCommand:此 Command 對象用於更新數據庫中的現有記錄。
InsertCommand:此 Command 對象用於向數據庫中插入新記錄。
DeleteCommand:此 Command 對象用於刪除數據庫中的現有記錄。
圖 1:用於訪問存儲過程的主要 ADO.Net 類以及它們之間的關系
到目前為止,您所看到的演示軟件示例可能將其 Command 對象配置為使用 SQL 語句進行數據訪問。實際上,某些示例可能完全跳過了 Command 對象的創建,這是因為 DataAdapter 的某個構造函數允許 Command 對象選擇後台創建的數據。在使用存儲過程之前,讓我們運行這樣一個示例進行比較。
本文中的所有示例都使用 SQL Server 附帶的 Northwind 示例數據庫。我們還使用專門為 SQL Server 創建的 ADO.Net 類,而不是普通的 OLE DB 類。為了便於訪問這些 SQL Server 類,所有示例都需要在應用程序的代碼頂部加上以下代碼行:
Imports System.Data.SQLClIEnt
現在,讓我們看看不使用存儲過程執行數據訪問的第一個示例。在此示例中,我們將在 Northwind 數據庫 Products 表中檢索所有產品。創建一個新 Windows 應用程序,在出現的空白 Form1 上,放置一個按鈕和一個 DataGrid。將 DataGrid 的 Anchor 屬性設置為全部四個邊,使之隨表單的擴展而擴展。在按鈕的 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.Tables("Products")
根據計算機配置的不同,可能需要更改連接字符串。建立數據庫連接後,其余代碼應該可以正常運行。此演示軟件說明了填入和使用 DataSet 的最簡單方法。
請注意,代碼並不創建 Connection 對象或 Command 對象。事實上,沒有這些對象,ADO.Net 便無法工作,但它們是在後台創建並使用的。實例化 SqlDataAdapter 的代碼行傳入 SQL 字符串(用於配置後台 Command 對象)和連接字符串(用於配置後台 Connection 對象)。
我們可以將此代碼更改為使用顯式 Connection 和 Command 對象,以便稍稍遠離演示軟件。在表單上再放置一個按鈕,並將以下代碼放到 Click 事件中:
Dim sConnectionString As String = _
"server=localhost;uid=sa;pwd=;database=Northwind"
Dim sSQL As String = "SELECT * FROM Products"
Dim cnNorthwind As New SqlConnection(sConnectionString)
Dim cmdProducts As New SqlCommand(sSQL, cnNorthwind)
Dim daGetProducts As New SqlDataAdapter(cmdProducts)
Dim dsProducts As New DataSet()
daGetProducts.Fill(dsProducts, "Products")
DataGrid1.DataSource = dsProducts.Tables("Products")
此代碼通過顯式創建 Connection 和 Command 對象,並將這些對象附加到 DataAdapter,說明了 DataAdapters 的常用性。通過在實例化 DataAdapter 時傳入 cmdProducts,DataAdapter 的 SelectCommand 將自動設置。然後,可以立即使用 DataAdapter 訪問數據庫。
此代碼的結果與前一示例中的結果相同。盡管它有點接近真實軟件,但由於數據訪問是通過 SQL 語句實現的,因此仍然屬於演示軟件。
使用簡單存儲過程獲取數據
如何將此演示軟件更改為使用存儲過程?只需更改幾行代碼。在表單上再放置一個按鈕,並將以下代碼放到 Click 事件中:
Dim sConnectionString As String = _
"server=localhost;uid=sa;pwd=;database=Northwind"
Dim cnNorthwind As New SqlConnection(sConnectionString)
Dim cmdProducts As New _
SqlCommand("十件最貴的產品", cnNorthwind)
cmdProducts.CommandType = CommandType.StoredProcedure
Dim daGetProducts As New SqlDataAdapter(cmdProducts)
Dim dsProducts As New DataSet()
daGetProducts.Fill(dsProducts, "Products")
DataGrid1.DataSource = dsProducts.Tables("Products")
實例化 Command 對象時,此代碼不使用 SQL 語句並替換為要使用的存儲過程名稱。此外,Command 對象的 CommandType 屬性必須設置為 StoredProcedure。
此後的代碼與上一個示例非常相似,但它返回不同的數據。存儲過程查找十件最貴的產品,並只返回每個產品的名稱和價格。
帶輸入參數的存儲過程
此示例很簡單,因為存儲過程不需要任何輸入參數。也就是說,查找十件最貴的產品不需要任何外部信息。無需外界幫助,存儲過程即可完成此操作。然而,多數存儲過程都需要輸入參數來執行其功能。在下一個示例中,讓我們看看如何向存儲過程傳遞輸入參數。我們將使用 CustomerID 來獲取相關客戶的所有訂單,並使用名為 CustOrderHist 的存儲過程(已存在於 Northwind 數據庫中)。
在已使用的表單上再創建一個按鈕,並將以下代碼行放到按鈕的 Click 事件後面:
Dim sConnectionString As String = _
"server=localhost;uid=sa;pwd=;database=Northwind"
Dim cnNorthwind As New SqlConnection(sConnectionString)
Dim cmdOrders As New SqlCommand("CustOrderHist", cnNorthwind)
cmdOrders.CommandType = CommandType.StoredProcedure
' 為存儲過程設置參數
Dim prmCustomerID As New SqlParameter()
prmCustomerID.ParameterName = "@CustomerID"
prmCustomerID.SqlDbType = SqlDbType.VarChar
prmCustomerID.Size = 5
prmCustomerID.Value = "ALFKI"
cmdOrders.Parameters.Add(prmCustomerID)
Dim daGetOrders As New SqlDataAdapter(cmdOrders)
Dim dsOrders As New DataSet()
daGetOrders.Fill(dsOrders, "Orders")
DataGrid1.DataSource = dsOrders.Tables("Orders")
此代碼與上一