小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

數(shù)據(jù)訪問(wèn): 在 Visual Basic .NET 中使用存儲(chǔ)過(guò)程1

 ycgclf 2011-01-06

在 Visual Basic .NET 中使用存儲(chǔ)過(guò)程

發(fā)布日期: 4/1/2004 | 更新日期: 7/6/2004

Billy Hollis

摘要:Billy Hollis 講述了存儲(chǔ)過(guò)程對(duì)于復(fù)雜系統(tǒng)的益處,將存儲(chǔ)過(guò)程提到了超出演示軟件的高度,并提供了一些手頭的示例,以說(shuō)明如何訪問(wèn)存儲(chǔ)過(guò)程以及如何開(kāi)始在應(yīng)用程序中使用這些存儲(chǔ)過(guò)程。

下載 StoredProcVB.NET.exe。

我們這些作者傾向于將軟件分為兩類(lèi):實(shí)際軟件演示軟件。 實(shí)際軟件就是那些在現(xiàn)實(shí)中能夠真正運(yùn)作的軟件。 演示軟件則是為了說(shuō)明某些編程概念而編寫(xiě)的軟件。

各種文章和書(shū)籍上所見(jiàn)到的大多數(shù)代碼都是演示軟件。 這些軟件必須比實(shí)際軟件來(lái)得簡(jiǎn)單;否則,讀者將陷入與所說(shuō)明概念毫無(wú)關(guān)系的各種細(xì)節(jié)中。 但有時(shí)演示軟件簡(jiǎn)單得過(guò)了火。 一味追求簡(jiǎn)單就可能忽略在編寫(xiě)實(shí)際軟件時(shí)所必需的一些細(xì)節(jié)。

我最近注意到的這種例子是關(guān)于數(shù)據(jù)訪問(wèn)的。 我所看到的每個(gè)數(shù)據(jù)訪問(wèn)示例基本上都使用 SQL 語(yǔ)句對(duì)關(guān)系數(shù)據(jù)庫(kù)進(jìn)行讀寫(xiě)訪問(wèn),這樣的關(guān)系數(shù)據(jù)庫(kù)如 Microsoft SQL Server?。 然而,在現(xiàn)實(shí)中,這種做法被認(rèn)為是一種錯(cuò)誤的編程習(xí)慣,可能一些小型的、有限的系統(tǒng)除外。 一個(gè)恰當(dāng)構(gòu)造的 n 層應(yīng)用程序使用存儲(chǔ)過(guò)程進(jìn)行數(shù)據(jù)訪問(wèn),而不是使用 SQL 語(yǔ)句。

在概念上,存儲(chǔ)過(guò)程類(lèi)似于程序中的函數(shù)。 存儲(chǔ)過(guò)程獲得輸入?yún)?shù),以黑盒子 形式運(yùn)行,并返回適當(dāng)?shù)男畔ⅰ?與函數(shù)的不同之處在于,存儲(chǔ)過(guò)程由數(shù)據(jù)庫(kù)引擎執(zhí)行,而不是在程序內(nèi)部執(zhí)行的。 這意味著必須利用一種能夠與數(shù)據(jù)庫(kù)接口的技術(shù)從存儲(chǔ)過(guò)程獲取信息或向其中輸入信息。 在 Microsoft Visual Basic? 6.0 中,這個(gè)技術(shù)就是傳統(tǒng)的 ADO。 在 Visual Basic .NET 中,我們則可以通過(guò) ADO.NET 完成。

如同對(duì)很多編程任務(wù)一樣,Visual Basic .NET 使得利用存儲(chǔ)過(guò)程訪問(wèn)數(shù)據(jù)的操作比 Visual Basic 6.0 利用存儲(chǔ)過(guò)程進(jìn)行數(shù)據(jù)訪問(wèn)容易得多。 Visual Basic .NET 提供了一些向?qū)б詭椭瓿纱诉^(guò)程,只要您知道如何避免一些太隨意的語(yǔ)句,即便是利用 ADO.NET 從頭開(kāi)始編寫(xiě)這種邏輯也不是過(guò)分復(fù)雜的事情。

本文包括一些在利用 ADO.NET 對(duì)存儲(chǔ)過(guò)程進(jìn)行操作時(shí)的基本方法,首先介紹了一種只讀操作,然后繼續(xù)講述使用存儲(chǔ)過(guò)程進(jìn)行插入、刪除和更新數(shù)據(jù)。

即便您不能熟練地編寫(xiě)存儲(chǔ)過(guò)程,您也將從本文中獲益匪淺。 大型編程團(tuán)隊(duì)中的很多開(kāi)發(fā)人員都需要能夠使用由別人編寫(xiě)的存儲(chǔ)過(guò)程。 我們的示例之一就是需要將一個(gè)存儲(chǔ)過(guò)程插入到示例數(shù)據(jù)庫(kù)中,但我們將循序漸進(jìn)地講述該項(xiàng)任務(wù)。

簡(jiǎn)要回顧 ADO.NET

對(duì)本文而言,我必須假設(shè)您已經(jīng)具備了有關(guān) ADO.NET 的基礎(chǔ)知識(shí)。如果您尚未使用 ADO.NET 中的 DataAdapters、DataSetsCommand 對(duì)象完成一些任務(wù),那么您應(yīng)該讀讀有關(guān) ADO.NET 的入門(mén)文章,包括 Rocky 為本專(zhuān)欄撰寫(xiě)的一篇文章,名為 ADO.NET and You。

簡(jiǎn)要回顧一下,DataSets 在 ADO.NET 中用作數(shù)據(jù)容器,在從數(shù)據(jù)庫(kù)斷開(kāi)時(shí)使用。 DataSet 包含一個(gè)或多個(gè) DataTables,其中每個(gè)包含一個(gè)行集。 對(duì)于熟悉傳統(tǒng)的 ADO 的開(kāi)發(fā)人員而言,DataTable大致可看作是一個(gè)斷開(kāi)的記錄集。

DataAdapters 在連接到數(shù)據(jù)庫(kù)時(shí)起作用。 一個(gè) DataAdapter 的任務(wù)或者是利用來(lái)自數(shù)據(jù)庫(kù)的數(shù)據(jù)填充其中一個(gè) DataTables,或者是將 DataTable 中的更改寫(xiě)回?cái)?shù)據(jù)庫(kù)中,或者是這二者都進(jìn)行。

DataAdapters 需要 Command 對(duì)象來(lái)執(zhí)行各種數(shù)據(jù)庫(kù)操作。 Command 對(duì)象中或者包含一條 SQL 語(yǔ)句,或者包含一個(gè)存儲(chǔ)過(guò)程名稱(chēng),用以指定要如何完成數(shù)據(jù)訪問(wèn)。 每個(gè) DataAdapter都有四個(gè)屬性,表明用于四種數(shù)據(jù)訪問(wèn)類(lèi)型中每一種類(lèi)型的命令對(duì)象:

SelectCommandCommand 對(duì)象用于從數(shù)據(jù)庫(kù)中選擇數(shù)據(jù)。

UpdateCommandCommand 對(duì)象用于更新數(shù)據(jù)庫(kù)中現(xiàn)有的記錄。

InsertCommand: Command 對(duì)象用于向數(shù)據(jù)庫(kù)中插入新記錄。

DeleteCommandCommand 對(duì)象用于刪除數(shù)據(jù)庫(kù)中現(xiàn)有的記錄。

我們可以用圖的形式來(lái)表示這些對(duì)象及其關(guān)系,如圖 1 所示。

bdadotnetarch08_03

1. 用于訪問(wèn)存儲(chǔ)過(guò)程的主要 ADO.NET 類(lèi),及其相互關(guān)系

到目前為止,您所看到的演示軟件示例可能都是將其 Command 對(duì)象配置為利用 SQL 語(yǔ)句進(jìn)行數(shù)據(jù)訪問(wèn)。 實(shí)際上,其中的某些示例很可能還完全繞過(guò)了 Command 對(duì)象的創(chuàng)建,因?yàn)?DataAdapter的其中一個(gè)構(gòu)造函數(shù)允許在后臺(tái)創(chuàng)建用于選擇數(shù)據(jù)的 Command 對(duì)象。 在開(kāi)始使用存儲(chǔ)過(guò)程之前,讓我們演示這樣一個(gè)示例以作為比較。

本文中所有示例都使用 SQL Server 所附帶的 Northwind 示例數(shù)據(jù)庫(kù)。 我們還將使用專(zhuān)門(mén)針對(duì) SQL Server 而創(chuàng)建的 ADO.NET 類(lèi),而不是使用通用的 OLE DB 類(lèi)。 為了便于訪問(wèn)這些 SQL Server 類(lèi),所有示例都需要在應(yīng)用程序的代碼最上面包括以下一行:

 Imports System.Data.SQLClient

現(xiàn)在,開(kāi)始我們的第一個(gè)示例,即不通過(guò)存儲(chǔ)過(guò)程執(zhí)行數(shù)據(jù)訪問(wèn)。 在此示例中,我們將檢索 Northwind 數(shù)據(jù)庫(kù) Products 表中所有的產(chǎn)品。 創(chuàng)建一個(gè)新的 Windows 應(yīng)用程序,并在所顯示的空白 Form1 上放置一個(gè)按鈕和一個(gè) DataGrid。 將 DataGridAnchor 屬性設(shè)置到全部四條邊,這樣一來(lái),它就會(huì)隨著窗體的擴(kuò)展而擴(kuò)展。 在按鈕的 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")

根據(jù)計(jì)算機(jī)的具體配置,您可能需要更改連接字符串。 然而,只要建立了數(shù)據(jù)庫(kù)連接,代碼的其他部分就應(yīng)該運(yùn)行正常。 此演示軟件顯示了用于填充和使用 DataSet 的最簡(jiǎn)單且可行的方法。

請(qǐng)注意,該代碼并沒(méi)有創(chuàng)建 Connection 對(duì)象或 Command 對(duì)象。 在現(xiàn)實(shí)中,如果沒(méi)有這些對(duì)象,ADO.NET 是不能運(yùn)行的,但這些對(duì)象是在后臺(tái)創(chuàng)建并使用的。 用于實(shí)例化 SqlDataAdapter 的代碼行傳遞進(jìn)來(lái)一個(gè) SQL 字符串(以配置這個(gè)后臺(tái) Command 對(duì)象)和一個(gè)連接字符串(以配置這個(gè)后臺(tái) Connection 對(duì)象)。

我們可以更改此代碼以使用顯式的 ConnectionCommand 對(duì)象,這樣離演示軟件稍微遠(yuǎn)了一些。 在窗體上放置另一個(gè)按鈕,并將以下代碼加入該按鈕的 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")

此代碼顯示了 DataAdapters 的更常見(jiàn)的使用方法;即通過(guò)顯式創(chuàng)建 ConnectionCommand 對(duì)象并將這些對(duì)象附加到 DataAdapter。 通過(guò)在實(shí)例化 DataAdapter 時(shí)傳遞到 cmdProducts 中,DataAdapterSelectCommand 得以自動(dòng)設(shè)置。 隨后,DataAdapter 馬上就可用于訪問(wèn)數(shù)據(jù)庫(kù)。

此代碼的結(jié)果與前一示例的結(jié)果完全相同。 但這段代碼較接近于真實(shí)軟件,它的更多方面還是像演示軟件,因?yàn)閿?shù)據(jù)訪問(wèn)是通過(guò) SQL 語(yǔ)句完成的。

利用簡(jiǎn)單的存儲(chǔ)過(guò)程獲取數(shù)據(jù)

如何更改此演示軟件以使用存儲(chǔ)過(guò)程呢? 只需更改其中的兩行。 在窗體上放置另一個(gè)按鈕,并將以下代碼加入該按鈕的 Click 事件中:

 Dim sConnectionString As String = _
"server=localhost;uid=sa;pwd=;database=Northwind"
Dim cnNorthwind As New SqlConnection(sConnectionString)
Dim cmdProducts As New _
SqlCommand("Ten Most Expensive Products", 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")

這段代碼不再使用 SQL 語(yǔ)句,取而代之的是在實(shí)例化 Command 對(duì)象時(shí)將使用存儲(chǔ)過(guò)程名稱(chēng)。 此外,該 Command對(duì)象的 CommandType 屬性必須設(shè)置為 StoredProcedure

從該行以后,代碼與前一示例完全相同,但返回不同的數(shù)據(jù)。 該存儲(chǔ)過(guò)程會(huì)找出十項(xiàng)最貴的產(chǎn)品,且僅返回每項(xiàng)產(chǎn)品的名稱(chēng)和價(jià)格。

帶輸入?yún)?shù)的存儲(chǔ)過(guò)程

此示例相當(dāng)簡(jiǎn)單,因?yàn)槠浯鎯?chǔ)過(guò)程不需要任何輸入?yún)?shù)。 也就是說(shuō),找出十項(xiàng)最貴產(chǎn)品的操作并不需要任何外部信息。 該存儲(chǔ)過(guò)程不需要任何外部幫助即可完成操作。 然而,大多數(shù)存儲(chǔ)過(guò)程卻的確需要輸入?yún)?shù)以執(zhí)行其功能。 作為下一個(gè)示例,讓我們看看如何向存儲(chǔ)過(guò)程傳遞輸入?yún)?shù)。 我們將利用 Northwind 數(shù)據(jù)庫(kù)中已有的一個(gè)名為 CustOrderHist 的存儲(chǔ)過(guò)程,并使用 CustomerID 獲取相關(guān)客戶(hù)的所有訂單。

在我們一直使用的窗體上創(chuàng)建另一個(gè)按鈕,并在該按鈕的 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
' Set up parameter for stored procedure
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")

這段代碼看起來(lái)很像前一示例中的代碼,不同之處在于,在創(chuàng)建 Command 對(duì)象之后,為該對(duì)象配置了一個(gè) Parameter對(duì)象并將其添加到了該命令的參數(shù)集合中。 在此示例中,我們硬編碼了一個(gè)客戶(hù) ID(更接近于演示軟件),而且在通常情況下參數(shù)的 Value屬性應(yīng)該被設(shè)置成某些用戶(hù)輸入數(shù)據(jù)。 然而,可完全按此示例中所示的方式設(shè)定該參數(shù)的其他屬性。

此示例顯式地設(shè)置了所有參數(shù)。 有些開(kāi)發(fā)人員喜歡這種風(fēng)格,且這種風(fēng)格適用于指導(dǎo)目的。 然而,有些開(kāi)發(fā)人員更喜歡另一種等效的形式,這種形式的代碼行更少:

 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
cmdOrders.Parameters.Add(New _
SqlParameter("@CustomerID", SqlDbType.VarChar, 5))
cmdOrders.Parameters("@CustomerID").Value = "ALFKI"
Dim daGetOrders As New SqlDataAdapter(cmdOrders)
Dim dsOrders As New DataSet()
daGetOrders.Fill(dsOrders, "Orders")
DataGrid1.DataSource = dsOrders.Tables("Orders")

這段代碼的功能與前一示例的功能完全相同。 然而,對(duì)每個(gè)參數(shù),它只需兩行代碼,而不是六行。 如果一個(gè)存儲(chǔ)過(guò)程具有很多參數(shù)(稍后的一些示例就會(huì)有很多參數(shù)),這樣一來(lái)所需的代碼行數(shù)可能會(huì)產(chǎn)生很大的區(qū)別,所以從此往后,我們將使用這種形式。

使用存儲(chǔ)過(guò)程更新數(shù)據(jù)庫(kù)

以上的幾個(gè)示例使用了存儲(chǔ)過(guò)程從數(shù)據(jù)庫(kù)中獲取信息。 在一些復(fù)雜的應(yīng)用程序中,也經(jīng)常使用存儲(chǔ)過(guò)程來(lái)更新、插入和刪除記錄。 讓我們看看如何利用 ADO.NET 進(jìn)行這些操作。

作為第一個(gè)示例,我們將允許 Visual Studio? .NET 中的向?qū)槲覀兙帉?xiě)一組存儲(chǔ)過(guò)程,并創(chuàng)建相應(yīng)代碼以使用這些過(guò)程。 盡管我們只需為此示例編寫(xiě)最少量的代碼,但是仔細(xì)查看向?qū)鶆?chuàng)建的代碼能夠幫助我們理解與存儲(chǔ)過(guò)程接口的過(guò)程,以便除獲取數(shù)據(jù)之外還可以進(jìn)行其他操作。

對(duì)于本示例,我們將使用 Northwind 示例數(shù)據(jù)庫(kù)中的 Customers 表。 在安裝 Northwind 數(shù)據(jù)庫(kù)時(shí),其中并不包含用于更新、插入或刪除客戶(hù)的存儲(chǔ)過(guò)程,但 Visual Studio .NET 中的 DataAdapter 配置向?qū)Э珊芊奖愕鼐帉?xiě)一些存儲(chǔ)過(guò)程。

開(kāi)始一個(gè)新的 Windows Application 項(xiàng)目。 在空白的 Form1 上,放置一個(gè) DataGrid和兩個(gè)按鈕。 跟前面一樣,將 DataGridAnchor 屬性更改為定位到所有四條邊。 將按鈕命名為 btnFillbtnUpdate,并將其 Text 屬性分別更改為 FillUpdate。

轉(zhuǎn)至 ToolboxData 選項(xiàng)卡,將一個(gè) SqlDataAdapter 控件拖到窗體上然后釋放。 這樣將打開(kāi)一個(gè) DataAdapter 配置向?qū)А?單擊 Next 按鈕,開(kāi)始在向?qū)е休斎胄畔ⅰ?/p>

首先,需要選擇一個(gè)到 Northwind 數(shù)據(jù)庫(kù)的連接,或者,如果列表中沒(méi)有可用連接,則單擊 New Connection按鈕,創(chuàng)建一個(gè)連接。 然后單擊 Next 按鈕。

下一個(gè)屏幕中包含用于訪問(wèn)數(shù)據(jù)的三種可選途徑。 該屏幕如圖 2 所示。

bdadotnetarch08_03

2. DataAdapter 選擇數(shù)據(jù)訪問(wèn)類(lèi)型

在此處,大多數(shù)演示軟件示例會(huì)使用第一個(gè)選項(xiàng)以使用 SQL 語(yǔ)句。 然而,我們將改用第二個(gè)選項(xiàng),并讓向?qū)槲覀儎?chuàng)建一些存儲(chǔ)過(guò)程。 選擇 Create new stored procedures 選項(xiàng),然后單擊 Next 按鈕。

下一個(gè)屏幕需要一條 SQL 語(yǔ)句以指明初始時(shí)從數(shù)據(jù)庫(kù)中獲取的數(shù)據(jù)。 然而,并不會(huì)直接使用此 SQL 語(yǔ)句。 此 SQL 語(yǔ)句中的信息將用于構(gòu)建進(jìn)行實(shí)際數(shù)據(jù)訪問(wèn)的存儲(chǔ)過(guò)程。 為了使此示例保持簡(jiǎn)單明了,請(qǐng)輸入 SQL 語(yǔ)句 SELECT * FROM Customers,然后按 Next 按鈕。

在此處,向?qū)б筇峁⒁獎(jiǎng)?chuàng)建的存儲(chǔ)過(guò)程的名稱(chēng)。 有四個(gè)存儲(chǔ)過(guò)程 — 選擇、更新、插入和刪除操作。 按以下方式命名:

選擇:MSDNSelectCustomers

更新:MSDNUpdateCustomer

插入:MSDNInsertCustomer

刪除:MSDNDeleteCustomer

保持選中 Yes, create them in the database for me 選項(xiàng)。 此時(shí),向?qū)聊粦?yīng)該類(lèi)似圖 3 所示。

bdadotnetarch08_03

3. DataAdapter 向?qū)⒁獎(jiǎng)?chuàng)建的存儲(chǔ)過(guò)程命名

單擊 Next 按鈕。 向?qū)?chuàng)建這些存儲(chǔ)過(guò)程,并在狀態(tài)屏幕上顯示其進(jìn)度。 完成后,您可以單擊 Finish按鈕,退出向?qū)А?/p>

該向?qū)?chuàng)建了一個(gè)完全配置好的 DataAdapter,但并未創(chuàng)建 DataSet 來(lái)容納數(shù)據(jù)。 下一步,我們將進(jìn)行該操作。 從 ToolboxData 選項(xiàng)卡中,拖過(guò)一個(gè) DataSet 控件。 當(dāng)顯示其配置屏幕時(shí),選擇 Untyped dataset。

現(xiàn)在,就可利用該 DataAdapter 填充該數(shù)據(jù)集了。 在 btnFillClick事件中,加入以下兩行代碼:

 SqlDataAdapter1.Fill(DataSet1, "Customers")
DataGrid1.DataSource = DataSet1.Tables("Customers")

btnUpdateClick 事件中,加入以下一行:

 SqlDataAdapter1.Update(DataSet1, "Customers")

現(xiàn)在,我們就擁有了一個(gè)可正常工作的演示軟件,它使用存儲(chǔ)過(guò)程進(jìn)行數(shù)據(jù)訪問(wèn)。 您可以運(yùn)行該程序,并單擊 Fill 按鈕以獲取網(wǎng)格中的用戶(hù)列表。 然后,您可以在網(wǎng)格中編輯用戶(hù)數(shù)據(jù),并選擇 Update 按鈕將這些更改返回到數(shù)據(jù)庫(kù)中。

如果編輯第一列,也就是 CustomerID,將發(fā)生異常,因?yàn)槟荒茉?SQL Server 中更新一條數(shù)據(jù)庫(kù)記錄中的主鍵。

查看一下向?qū)傻拇a還是很有指導(dǎo)意義的,所有這些代碼最初都隱藏在 Windows Form Designer generated code 區(qū)域中。 單擊該區(qū)域相應(yīng)的加號(hào),展開(kāi)該代碼。 注意以下代碼,這些代碼會(huì)實(shí)例化 SQLDataAdapter及其所需的四個(gè)命令對(duì)象:

 Me.SqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter()
Me.SqlSelectCommand1 = New System.Data.SqlClient.SqlCommand()
Me.SqlInsertCommand1 = New System.Data.SqlClient.SqlCommand()
Me.SqlUpdateCommand1 = New System.Data.SqlClient.SqlCommand()
Me.SqlDeleteCommand1 = New System.Data.SqlClient.SqlCommand()

再往下,您將看到用于配置每個(gè)命令對(duì)象并為其創(chuàng)建參數(shù)集合的代碼。 這段代碼類(lèi)似于前面的使用帶參數(shù)的存儲(chǔ)過(guò)程的示例中的代碼。 然而,向?qū)傻拇a使用了附加的一些參數(shù)屬性,以允許這些參數(shù)屬性與更改數(shù)據(jù)的各種存儲(chǔ)過(guò)程一起使用。 例如,用于為 SQLInsertCommand1 創(chuàng)建 CompanyName 參數(shù)的代碼:

 Me.SqlInsertCommand1.Parameters.Add(New _
System.Data.SqlClient.SqlParameter("@CompanyName", _
System.Data.SqlDbType.NVarChar, 40, "CompanyName"))

在前面的示例中,我們僅為參數(shù)名稱(chēng)、數(shù)據(jù)類(lèi)型和長(zhǎng)度設(shè)置了屬性。 這段代碼還將該參數(shù)的 SourceColumn 屬性設(shè)置為 CompanyName 值。 該屬性表明了該數(shù)據(jù)集的 CustomersDataTable 中與此參數(shù)對(duì)應(yīng)的字段。 這就允許在插入操作中將 DataTable 中的值自動(dòng)插入該參數(shù)的 Value 屬性中。 讓我們更詳細(xì)地討論一下這一點(diǎn)。

當(dāng) SQLDataAdapterUpdate 方法被調(diào)用時(shí),它會(huì)更新 DataSet 中的單個(gè) DataTable。 對(duì) DataTable 逐行進(jìn)行檢查,查找需要更新、插入或刪除的行。 當(dāng)發(fā)現(xiàn)要將新的一行插入數(shù)據(jù)庫(kù)時(shí),SQLDataAdapter 會(huì)使用其 InsertCommand 屬性所設(shè)定的 Command 對(duì)象。 在這里,該 Command 對(duì)象訪問(wèn)了 MSDNInsertCustomer 存儲(chǔ)過(guò)程。

在能運(yùn)行該存儲(chǔ)過(guò)程之前,必須從正被插入的行填充每個(gè)參數(shù)的 Value 屬性。 用于配置 SQLDataAdapter1的代碼將該存儲(chǔ)過(guò)程的每個(gè)參數(shù)與 DataTable 中的相應(yīng)字段關(guān)聯(lián)起來(lái)。 這就允許將新的 DataTable 行的數(shù)據(jù)自動(dòng)傳送到該存儲(chǔ)過(guò)程的參數(shù)。

其他存儲(chǔ)過(guò)程的參數(shù)可類(lèi)似地進(jìn)行配置。 有一個(gè)不同之處值得注意。 其他存儲(chǔ)過(guò)程會(huì)傳入 DataTable中數(shù)據(jù)的初始值,這些值用于檢查數(shù)據(jù)在您不知情的情況下未發(fā)生更改。 也就是說(shuō),如果您獲取了某些數(shù)據(jù),而在您嘗試更新之前別人已經(jīng)進(jìn)行了更改,您則會(huì)得到一個(gè)并發(fā)異常。 啟動(dòng)上述程序,獲取客戶(hù)信息,然后使用某個(gè)工具(如 SQL Enterprise Manager)更改記錄中的某項(xiàng)內(nèi)容,您就可以看到這種情況發(fā)生。 如果您在示例程序中更改同一條記錄并試圖更新,則會(huì)得到一個(gè)并發(fā)異常。

從存儲(chǔ)過(guò)程返回值

以上示例在一個(gè)方面存在著不足。 Northwind Customers 表使用了字母數(shù)字主鍵,且應(yīng)用程序在插入數(shù)據(jù)時(shí)必須組成這些主鍵。 也就是說(shuō),如果您利用以上的程序插入一條新記錄,則必須自己為 CustomerID 創(chuàng)建一個(gè) 5 個(gè)字符的值。

在實(shí)際軟件中,更常見(jiàn)的做法是為新記錄自動(dòng)生成主鍵。 這種主鍵通常是一個(gè)按順序分配的長(zhǎng)整數(shù)。

有兩種基本方法可用于為新記錄設(shè)置主鍵。 應(yīng)用程序可以調(diào)用一個(gè)存儲(chǔ)過(guò)程以生成下一個(gè)可用的 ID,然后該應(yīng)用程序可以將該 ID 直接放入 DataSet 的新行中。 或者,用于插入記錄的存儲(chǔ)過(guò)程可以為該記錄派生新的 ID,然后作為一個(gè)返回值將其傳遞回該應(yīng)用程序中。

第一種方法需要一些額外的邏輯以獲取新 ID 并將其放到新記錄中的合適位置處。 使用存儲(chǔ)過(guò)程進(jìn)行插入操作與以上的示例類(lèi)似。

然而,第二種方法需要一種新的參數(shù)用于存儲(chǔ)過(guò)程。 到目前為止,我們所見(jiàn)到的所有參數(shù)都是默認(rèn)類(lèi)型,也就是一個(gè)輸入?yún)?shù)。 實(shí)際上,有四種類(lèi)型的參數(shù):

Input

這種參數(shù)僅用于將信息從應(yīng)用程序傳遞到存儲(chǔ)過(guò)程。

InputOutput

這種參數(shù)可以將信息傳入存儲(chǔ)過(guò)程,也可將信息從存儲(chǔ)過(guò)程傳遞回應(yīng)用程序。

Output

這種參數(shù)只將信息從存儲(chǔ)過(guò)程傳遞回應(yīng)用程序。

ReturnValue

這種參數(shù)代表從存儲(chǔ)過(guò)程返回的值。 這種參數(shù)并不出現(xiàn)在 SQL Server 中用于存儲(chǔ)過(guò)程的參數(shù)列表中。 它只與存儲(chǔ)過(guò)程的 RETURN 語(yǔ)句中的某個(gè)值相關(guān)。

當(dāng)存儲(chǔ)過(guò)程為主鍵生成一個(gè)新值時(shí),常用的做法是利用該存儲(chǔ)過(guò)程中的一條 RETURN 語(yǔ)句返回該值,因此,用于訪問(wèn)該值的參數(shù)類(lèi)型是 ReturnValue 參數(shù)。

ReturnValue 參數(shù)與其他類(lèi)型的參數(shù)之間有一個(gè)重要的不同之處。 在通常情況下,在 ADO.NET 中為 Command對(duì)象配置各個(gè)參數(shù)的順序無(wú)關(guān)緊要。 各個(gè)參數(shù)的名稱(chēng)可用于將其與存儲(chǔ)過(guò)程中的相應(yīng)參數(shù)進(jìn)行匹配。 然而,對(duì)于 ReturnValue參數(shù)而言,它必須 是該列表中的第一個(gè)參數(shù)。

這就意味著,當(dāng)您為一個(gè) Command 對(duì)象配置 ReturnValue參數(shù)時(shí),必須在代碼中首先配置這個(gè)參數(shù),這樣它就可以獲取集合中的第一個(gè)數(shù)字索引。 如果您首先配置任何其他的參數(shù),ReturnValue參數(shù)將不會(huì)正常運(yùn)行。

為了演示帶返回值的存儲(chǔ)過(guò)程的使用,我們將執(zhí)行一個(gè)示例 — 將一條記錄插入 Northwind Products 表。 這個(gè)表被設(shè)置為利用一個(gè) Identity 列自動(dòng)生成新的產(chǎn)品 ID。 不巧的是,Northwind 示例數(shù)據(jù)庫(kù)中并不包含一個(gè)可完成我們想要的操作的存儲(chǔ)過(guò)程,因此,在進(jìn)行本示例的剩余部分之前,我們必須在數(shù)據(jù)庫(kù)中插入相應(yīng)的存儲(chǔ)過(guò)程。

轉(zhuǎn)至 Visual Studio .NET 中的 Server Explorer。 打開(kāi) SQL Server 節(jié)點(diǎn),然后打開(kāi)相應(yīng) SQL Server 實(shí)例的節(jié)點(diǎn)。 然后打開(kāi) Northwind 數(shù)據(jù)庫(kù)節(jié)點(diǎn)。

右鍵單擊 Stored Procedures 節(jié)點(diǎn),然后選擇 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

現(xiàn)在,關(guān)閉編輯窗口,將詢(xún)問(wèn)您是否想要保存更改,單擊 Yes。 該存儲(chǔ)過(guò)程已被保存在數(shù)據(jù)庫(kù)中,且將被命名為 MSDNInsertProduct。

現(xiàn)在,我們就可以編寫(xiě)代碼來(lái)使用該存儲(chǔ)過(guò)程了。 創(chuàng)建一個(gè)新的 Windows 應(yīng)用程序,在空白 Form1 上,放置一個(gè) DataGrid,并將其定位到所有四條邊。 另外,添加名為 btnFillbtnInsertProduct的兩個(gè)按鈕。 將 btnFillText 屬性設(shè)置為 Fill 而將 btnInsertProductText 屬性設(shè)置為 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

這段代碼與本文中前面所見(jiàn)的代碼幾乎完全相同,因此我們不再討論。 如有必要,不要忘記更改連接字符串,并將 SQLClient 命名空間的 Imports 語(yǔ)句放在該項(xiàng)目代碼的開(kāi)始位置處。 然后將以下代碼放到 btnInsertProductClick事件中。

 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
' Set up parameters for stored procedure
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"))

除了用于為返回值配置參數(shù)的各行外,這段代碼與我們前面所見(jiàn)的代碼很相似。 請(qǐng)注意,這是第一個(gè)參數(shù),設(shè)置此參數(shù)是為了將返回值放回到 ProductID 字段。

用于將新行插入數(shù)據(jù)集的代碼是標(biāo)準(zhǔn)的 ADO.NET 代碼,因此我們將不再詳述。 它為產(chǎn)品記錄創(chuàng)建一個(gè)具有合適結(jié)構(gòu)的新行(利用 products DataTableNewRow 方法),將數(shù)據(jù)放入行中,最后將該行加入 products DataTable 的 Rows 集合中。

現(xiàn)在,運(yùn)行該程序以進(jìn)行測(cè)試。 單擊 Fill 按鈕,但是不對(duì)網(wǎng)格中的任何數(shù)據(jù)進(jìn)行更改。 然后按 Insert Product按鈕。 將插入一條對(duì)應(yīng)于 Billy's Sesame Oil 的新產(chǎn)品記錄,且一個(gè)消息框?qū)@示針對(duì)該記錄返回的 ProductID。 您也可以在網(wǎng)格中打開(kāi) Products 表,滾動(dòng)瀏覽到底部,即可注意到已添加的新記錄。

使用 Server Explorer 編寫(xiě)參數(shù)代碼

以上的代碼編寫(xiě)起來(lái)乏味而重復(fù)。 然而,DataAdapter 配置向?qū)崾緦?shí)際上 Visual Studio 可以替我們編寫(xiě)這些代碼。 DataAdapter 配置向?qū)橐粋€(gè)完整配置中的所有四個(gè)存儲(chǔ)過(guò)程(SelectUpdate、InsertDelete 各一個(gè))生成代碼。 假設(shè)您正需要如上例所示的某一個(gè)存儲(chǔ)過(guò)程的代碼,那該如何呢? 您仍然可以走一條捷徑。 要獲得只是與一個(gè)存儲(chǔ)過(guò)程接口的預(yù)編寫(xiě)代碼,只需展開(kāi) Server Explorer 以顯示您想要使用的存儲(chǔ)過(guò)程,然后將該存儲(chǔ)過(guò)程拖到設(shè)計(jì)界面上即可。 您將看到只是為該存儲(chǔ)過(guò)程創(chuàng)建的 DataAdapterCommand對(duì)象,且該代碼的設(shè)計(jì)器部分將包含為該存儲(chǔ)過(guò)程配置各個(gè)參數(shù)所需的全部代碼。 您可原封不動(dòng)地使用該代碼,也可根據(jù)自己的需要而復(fù)制并改寫(xiě)該代碼。

小結(jié)

本文中的各個(gè)示例仍然是演示軟件,但是至少這些示例向您展示的使用存儲(chǔ)過(guò)程的相關(guān)信息足以使您開(kāi)始編寫(xiě)自己的軟件。 當(dāng)然了,您需要理解您將要使用的存儲(chǔ)過(guò)程,并且可能需要詢(xún)問(wèn)數(shù)據(jù)庫(kù)管理員 (DBA) 或其他小組成員以獲得這些信息。

對(duì)于復(fù)雜系統(tǒng)而言,存儲(chǔ)過(guò)程具有很多優(yōu)點(diǎn)。 我希望您已從本文中學(xué)習(xí)到足夠的知識(shí),而不會(huì)對(duì)開(kāi)始使用存儲(chǔ)過(guò)程而心存畏懼。 在最初的一些嘗試中,您可能想要使用 DataAdapter 向?qū)Щ蛘?Server Explorer 為您編寫(xiě)大多數(shù)代碼,但如果您能夠在需要的時(shí)候編寫(xiě)自己的訪問(wèn)代碼,那么您工作起來(lái)將事半功倍。

轉(zhuǎn)到原英文頁(yè)面


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多