Visual Studio 2005中的新DataSet特性(1)

本文,我將致力於在 Microsoft Visual Studio 2005 開發環境下使用這些類以及派生的類進行開發工作。對於類型化 DataSet 所作的更改和由 Visual Studio 2005 生成的新類型化 TableAdapter,是本文將要討論的具體內容。除此之外,爲開發以數據爲中心的應用程序而使用的設計器和工具也是本文要討論的內容,這些設計器和工具提供了很高的靈活性和工作效率。爲了解釋不同的概念和特性,我將逐步介紹開發人員在實現應用程序數據處理部分時通常要經歷的過程。代碼示例使用 Northwind 數據庫,該數據庫是 Microsoft SQL Server(以及 MSDE)7.0 版本和 Microsoft SQL Server 2000 自帶的示例數據庫。

  Visual Studio 2005 引入了項目數據源的概念。數據源代表在應用程序中可以使用的數據。數據庫不是這些數據的唯一來源,定義數據源所使用的 Data Source Configuration Wizard 允許您從三種不同的源獲取數據:

1.數據庫 — 既可以是基於服務器的數據庫(例如 SQL Server 或 Oracle),也可以是基於文件的數據庫(例如 Access 或 SQL Server Express)。Visual Studio 自動生成類型化 DataSet 及其他類,並將它們添加到項目。

2.對象 — 任何具有公共屬性的對象都可以是數據源。不一定非要實現某個特殊接口。

3.Web 服務 — 從 Web 服務創建的數據源,將創建與 Web 服務返回的數據類型相對應的對象。

  數據源具有事半功倍的作用。一方面,它可以使指定、設計和生成代表應用程序數據的強類型類更容易。另一方面,它提供一種靈活而統一的機制,可非常快速地構建功能豐富、運行高效的 WinForm 和 WebForms 用戶界面。在閱讀本文的過程中,您將瞭解到這是多麼得快速、簡單和靈活。

  數據庫 (DataSet) 數據源的創建及其在 WinForms 應用程序中的使用是本文的重點內容。但是,以下兩點也不容忽視:

一旦創建了數據源,就將以相同的方式使用每個數據源,而無需考慮其數據來自何處。也就是說,就像您可以輕鬆地將基於 Database 的數據源(以圖形方式)綁定到網格控件或一組控件上一樣,真正來自 Web 服務或您自定義業務對象的數據也要綁定到控件上。

無論是在 WinForms 還是在 WebForms 應用程序中使用,數據源均以同一種方式進行定義。不同的數據提供程序也進行了抽象,以便在只使用 DataSets 和 TableAdapters 公開數據訪問的情況下,只需更改連接字符串並重新生成類就可以更改實際使用的數據庫。

  類型化 DataSet 和 TableAdapter

  數據庫數據源就是一個強類型 DataSet 與一個或多個強類型 DataTables 和 TableAdapters 對的組合。類型化 DataSet 的概念並不陌生,在 Visual Studio 2002/2003 中就已經提出。雖然它是從 .NET Framework 的一般 DataSet 類派生的生成類,但它具有定義好的架構以及特定於該架構的屬性和方法。與此同時,DataSet 中的每個表還要生成其他三個特定於該 DataSet 的派生類 — DataTable、DataRow 和 DataRowChangeEvent 類。在這些類中,每個類都有針對相關表的特定架構、屬性和方法。例如,如果根據 Northwind Employees 表定義一個數據源,最終將生成以下類:

NorthwindDataSet

EmployeesDataTable

EmployeesDataRow

EmployeesRowChangeEvent

  這四個類就組成了一個類型化 DataSet。在 Visual Studio 2005 中還將生成第五個類,名爲 EmployeesTableAdapter 的類型化 TableAdapter,稍後我們將討論這個類。當然,如果您以動態方式定義查詢,那麼就不能生成類型化 DataSet,而是需要使用標準的 DataSet。

  爲什麼要爲類型化DataSet 而煩惱呢?因爲除了促使您預先考慮數據的架構,而非倉促決定之外,類型化 DataSet 還提供了一些實際的優點:

1.DataSets、DataTables、DataRows 和 RowChangeEvent 都特定於正在處理的架構。

2.表、列和關係是以命名的屬性方式公開的,而非一般的集合元素。

3.由於 (2) 的原因,Visual Studio 代碼編輯器將支持完整的智能感知和語句結束支持。

4.可以實現編譯時類型檢查,例如在編譯時而不是等到運行時就可以捕捉到字段名拼寫錯誤,這同樣是由於 (2) 的原因。

5.代碼更簡潔,可讀性更強。例如以下代碼行:

country = dsNorthwind.Tables ("Employees").Rows (row) ("Country")

可以替換爲

country = dsNorthwind.Employees (row).Country

  總而言之,類型化 DataSets 所提供的設計時和編譯時支持不但可以大大地減少啓動開發時間,而且可以減少調試和穩定應用程序所需的時間。

  此外,TableAdapter 是 Visual Studio 2005 新提出的概念。它意味着強類型 TableAdapter 就是標準 DataAdapter 的強類型等價類。您可以使用 TableAdapter 連接到數據庫,執行對數據庫的查詢或存儲過程,並將數據填寫到相關的 DataTable。每個 DataTable-TableAdapter 對都以一個 TableAdapter 指代。

  TableAdapter 實質上就是一個標準的 DataAdapter 的外部包裝程序,它提供以下一些好處:

同一個 TableAdapter 類可在多個窗體或組件上使用,因此任何對查詢/命令進行的更改都將自動在所有實例中反映出來。這不同於現有情形,在現有情形下,每個訪問數據庫的組件都必須擁有各自單獨配置的 DataAdapter。但是如果要確保 DataTables 和 DataAdapters 保持同步,這樣做將更容易。

如果要爲某個指定的 DataTable 定義多個查詢/命令,使用一個 TableAdapter 即可輕鬆完成,而不必使用多個 DataAdapters 或手動切換代碼。

Fill 命令的名字可讀性強、較友好,而且 TableAdapter 包含的代碼可以自動爲這些命令方法中的所有參數填加類型和值信息。您再也不需要將其以特定於提供程序的數據類型(例如 SqlInt)進行傳遞了。

  舉一個簡單的代碼片斷示例會有助於解釋這些特性。在 Visual Studio 2002/2003 中,即使使用了類型化 DataSet,執行一個帶有兩個參數的簡單查詢也需要不少的代碼。對於下列查詢

SELECT FirstName, LastName from Employees WHERE Country = @country AND City = @city

  我們必須按以下方式編寫代碼:

Me.SqlAdapter1.SelectCommand.Parameters ("@country").value =
Me.CountryListbox.SelectedValue.Trim()
Me.SqlAdapter1.SelectCommand.Parameters ("@city").value =
Me.CityTextbox.Text.Trim()
Me.SqlAdapter1.Fill (Me.NorthwindDataSet.Employees)

  毫無疑問,隨着參數數量的增長,代碼行數也將不斷增加。但更重要的是,正確地記憶和輸入所有參數名的機率卻大大降低了。即使準確記住了參數名,也仍然需要記住參數的數據類型。這還不是最糟糕的情況,如果錯誤地輸入了字段名或者爲值賦了錯誤的類型,那麼很可能到運行時纔會察覺。

  如果使用 Visual Studio 2005 中的 TableAdapter,一旦定義了命令 FillByCountryAndCity,在任何地方使用它時只需編寫一行代碼,將其以參數值形式傳遞即可:

Me.EmployeesTableAdapter.FillByCountryAndCity ( _
   Me.NorthwindDataSet.Employees, Me.CountryListbox.SelectedValue.Trim(),
      _    Me.CityTextbox.Text.Trim() )

  不容忽視的是,我們不僅可以從一個 TableAdapter 那裏取得多個命名命令,而且這些命令都是強類型的。這就意味着在 Visual Studio 中編寫代碼時,可以將這些命令視爲 TableAdapter 的方法,因爲我們獲得了完整的智能感知。我們還要對這些命令的參數進行編譯時類型檢查,同時,方法和參數類型定義的工具提示也可以助我們一臂之力。 TableAdapter 可以包含多個執行不同命令、接收不同參數的方法。現在我們要構建示例窗體,稍後再詳細介紹 TableAdapter。

 開始行動 — 創建數據源

  本文,我們將構建一個顯示 Northwind 數據庫中每個定單定購信息的窗體。打開一個新的 Visual Basic WinForms 項目後,首先必須做的事情是向項目中添加一個新數據源(在創建這一示例的過程中,我們將使用 Visual Basic,但所有的操作對於 C# 也適用)。

  添加一個數據源:

1.在 Visual Studio 主菜單中,選擇 Data 菜單項中的 Show Data Sources,即可顯示數據源窗口(在該窗口未顯示出來的情況下)。

2.在數據源窗口上,單擊 Add New Data Source 工具欄按鈕。該操作將啓動 Data Source Configuration Wizard,該向導將 DataAdapter Configuration Wizard 的大部分功能和 Visual Studio 2002/2003 中的 DataSet 生成工具結合在一起。

3.如果您的 Visual Studio 版本仍然包含嚮導的歡迎頁面,請選擇 Next。然後將顯示 Choose a Data Source Type 頁面。

4.選擇 Database。

5.選擇 Next,顯示 Choose Your Data Connection 頁面。

6.選擇 New Connection,顯示 Add Connection 對話窗口。

7.輸入要連接到 SQL Server(或 MSDE)實例以及 Northwind 數據庫所需的信息。

8.選擇 OK,關閉對話窗口。

9.注意,現在的連接字符串是保存爲一個設置屬性,可以通過下列語句訪問

My.Settings.NorthwindConnectionString

在 C# 中,該語句爲以下形式

VSDataSets.Properties.Settings.Default.NorthwindConnectionString;

10.選擇 Next,顯示 Choose Your Database Objects 頁面。

11.注意,可以選擇 TablesViews、Stored、Procedures 或 Functions。

展開 Tables 節點,然後選擇 Orders 和 Order Details 表。我們將使用表中的所有列,但您也可以只選擇應用程序所需的那些列。

12.選擇 Finish,退出嚮導。

圖 1 顯示 Order Details 表展開後的數據源窗口,圖中顯示了該表的所有列。



圖 1. 數據源窗口中的 Order Details 表

   如果要作出一些改動,重新輸入 Data Source Configuration Wizard,可以選擇數據源窗口工具欄的 Configure DataSet with Wizard,或者右鍵單擊該窗口中任何元素,從得到的上下文菜單中選擇嚮導。然而,編輯生成的 DataSet 和(多個)TableAdapter 更好的工具是 DataSet Designer。

  DataSet 設計器

  Visual Studio 2005 包含的 DataSetDesigner 是一個專門爲指定和編輯 DataSets 及其相關 TableAdapters 而設計的工具。與 Visual Studio 2002/2003 中的情形比較,它有了明顯的改進,因爲以前我們必須使用 XML 架構編輯器來定義強類型 DataSets。在這裏,DataSet 和 TableAdapter 的定義仍然保存在 .XSD 文件中,如果一定要編輯 XML 架構,也仍然是使用 XML 編輯器。不過,相似之處僅此而已。而且這樣做只是爲了文件格式方便起見,並不是爲了使 DataSetDesigner 支持任意的 XSD 文件。

  選擇數據源窗口工具欄中的 Edit DataSet with Designer,或者右鍵單擊該窗口中任何元素,從得到的上下文菜單中選擇使用設計器進行編輯,將進入 DataSet 設計器。在設計 DataSets 及其 DataTables 的過程中,設計者很可能會覺得該工具與過去設計數據庫使用的其他工具十分相似。要爲連接的數據庫添加表,可以將數據庫對象(例如表、視圖、存儲過程)從 Server Explorer 中拖放到設計器表面,或者在設計器上下文菜單的 Data 主菜單選項中選擇 Add TableAdapter,啓動 TableAdapter Configuration Wizard。因爲 DataSet 還可以包含不與數據庫連接而直接加載的表,所以還可以選擇菜單中的 Add DataTable 來添加一個單獨的表。在編輯器中同樣可以添加和/或重命名列。另一個乾淨利落的特性是,編輯器自動識別數據庫中各表之間的關係,在 DataSet 中爲您定義各表之間對應的 Relations。

  圖 2 顯示在 DataSet 設計器中,由 Orders 和 Order Details 表組成的數據源。注意,與每個 DataTable 密切相關的是其各自對應的 TableAdapter,用於爲表填寫數據,或者(可選)用改動後的數據更新數據庫。



圖 2. 數據源中的 Orders 和 Order Details 表

 TableAdapter Configuration Wizard

  選擇 Data 主菜單中的 Add Query 或 Configure(一個現有查詢),或者在設計器中右鍵單擊 TableAdapter,從得到的上下文菜單中選擇這兩項,可以啓動 DataSet 設計器中的 TableAdapter Configuration Wizard。此嚮導等同於 Visual Studio 2002/2003 的 DataAdapter Configuration Wizard,只不過多了兩個附加頁面。一個是圖 3 所示的 Choose a Query Type 頁面。由於 TableAdapter 彙集了針對給定表的所有命令,因此該頁面允許您定義多個 Select/Fill 命令和查詢 — 任何類型的查詢都可以,例如 Update、Insert、Delete 或返回單個值類型的查詢。切記,這些更新查詢是 TableAdapter 的命名方法,必須直接調用。而且它們還是執行 TableAdapter 的 Update 方法時自動調用的更新查詢,這與執行 DataAdapter.Update 方法一樣。

  嚮導中另一個增加的頁面是 Choose Methods to Generate 頁。在該頁中可以選擇您所定義的每個查詢/命令方法名(一個或多個)。嚮導爲每個命令都提供一個 Fill 和 Get 方法,如圖 3 所示。Fill 要求提供需要填寫數據的 DataTable,而 Get 方法將返回填寫後新創建的 DataTable。



圖 3. Choose Methods to Generate 頁面中的 Fill 和 Get 方法

  按照典型的用法,您可以爲一個 TableAdapter 定義多個 Fill 命令,它將返回同一種架構(多個列),只是 WHERE 子句不同而已。這也是默認情況下向導會爲方法名提供一個 FillBy 和 GetDataBy 前綴的原因。不過,您當然可以選擇任何名字作爲方法名。

  雖然 TableAdapter 可以包含多個 Fill 命令,但在調用其中的 Update 方法時卻只能執行一組更新命令。這組命令根據 TableAdapter 的主查詢自動生成。第一次創建 TableAdapter 時定義的查詢被認爲是它的主查詢。如果隨後定義的任何查詢返回的架構與主查詢的架構不同,則設計器將顯示一個消息框進行提醒。另一方面,如果您修改了主查詢的架構,Visual Studio 將修改其他查詢的架構以與之匹配。

  通過 TableAdapter Configuration Wizard 添加新命令

  現在,我們將另一個命令添加到 Orders 表的 TableAdapter。

1.選擇數據源窗口工具欄中的 Edit DataSet with Designer,打開 DataSet 設計器。

2.選擇 Orders 表的 TableAdapter,再從該表的上下文菜單中選擇 Add Query。

3.如果您的 Visual Studio 版本中仍然有 Welcome 頁,請選擇頁面上的 Next。之後,顯示 Choose a Command Type 頁面。

4.要接受默認的 SQL 語句,選擇 Next。這時顯示 Choose a Query Type 頁面。

5.要接受默認的 SELECT 語句,選擇 Next。然後,顯示 Specify a SQL SELECT Statement 頁面。

6.輸入下列 SQL 語句。

SELECT OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, 
ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, 
ShipRegion, ShipPostalCode, ShipCountry 
FROM Orders
WHERE CustomerID = @CustID

此後,返回由進行查詢的 @CustID 參數指定的所有客戶 Orders。

7.選擇 Next,顯示 Choose Methods to Generate 頁。

8.選中頁面上的兩個複選框。將方法名分別改爲 FillByCustomer 和 GetDataByCustomer。

9.選擇 Next,然後選擇 Finish,完成該過程。

  現在請您看一下 DataSet 設計器中的 OrdersTableAdapter,這時出現了第二個命令對 — FillByCustomer 和 GetDataByCustomer,CustomerID 的值就是該命令的一個參數。那麼,該方法的參數屬於哪種 .NET 類型呢?讓我們來討論一下。

  後臺簡介

  在 DataSet 設計器或任何相關嚮導中進行修改時,Visual Studio 都會爲一組類型化的類生成代碼。具體而言,它將生成以下類:

1.DataSet 類

2.DataTable 類

3.TableAdapter 類

4.DataRow 類

5.DataRowChangeEvent 類

  除了 DataSet 類(每個數據源只有一個)之外,其餘四個類對於 DataSet 中定義的表而言是相同的。可通過以下操作查看這些類的代碼:

1.在 Solution Explorer 窗口中,單擊工具欄上的 Show All Files 按鈕,顯示與項目相關的所有文件。

2.展開 NorthwindDataSet.xsd 文件的節點。

3.雙擊文件節點上的 NorthwindDataSet.Designer.vb。這就是爲實現組成 DataSet 的那些類而生成的代碼。

4.打開代碼窗口左上角的 Listbox,將看到本文所用類的列表:

NorthwindDataSet

Order_DetailsDataTable

OrdersDataTable

Order_DetailsRow

OrdersRow

Order_DetailsRowChangeEvent

OrdersRowChangeEvent

Order_DetailsTableAdapter

OrdersTableAdapter

5.選擇左側 Listbox 中的 OrdersTableAdapter 類。

6.再選擇右側 Listbox 中的 FillByCustomer 方法。此時將顯示該方法的代碼,如下所示:

      Public Overloads Overridable Function FillByCustomer(ByVal dataTable 
         As NorthwindDataSet.OrdersDataTable, ByVal CustID As String) As Integer
            Me.Adapter.SelectCommand = Me.CommandCollection(1)
            If (CustID Is Nothing) Then
                Throw New System.ArgumentNullException("CustID")
            Else
                Me.Adapter.SelectCommand.Parameters(0).Value = CType(CustID,String)
            End If
            If (Me.m_clearBeforeFill = true) Then
                dataTable.Clear
            End If
            Dim returnValue As Integer = Me.Adapter.Fill(dataTable)
            Return returnValue
        End Function

  從該代碼片斷中我們可以瞭解幾件事情。

FillByCustomer 方法實際上帶有兩個參數 — 一個是要填寫的 OrdersDataTable,另一個是字符串類型的 CustID 參數。

不用檢查完文件中的所有代碼,我們就可以發現 TableAdapter 類維護着一個命令集合,正是從這個集合中自動將正確的命令指派給 .NET DataAdapter,供其使用這些命令自動與數據庫通訊。

如果狀態參數的 AllowDBNull 屬性設置爲 False,該方法會不斷檢查是否有狀態參數的實例傳遞進來。

如果 DataAdapter 的 SelectCommand 屬性已經配置好,則 CustID 的參數值將賦給該屬性的參數。

所有配置設置完畢後,即可調用 DataAdapter.Fill () 方法來填寫 OrdersDataTable。

  切記,這些代碼都不需要您動手編寫。它們是已經生成並配置好的代碼。花些時間查找一下爲您生成的其他類。您將更深入、更廣泛地理解這些類的實現方式,甚至還可能學到幾個有用的編程技巧。

  注 儘管類型化 DataSet 及其相關類(包括 TableAdapters)均在一個源文件中生成,但 TableAdapters 是在某個獨立的命名空間中生成的。這說明應該將實體對象 (DataSets) 與真正的數據訪問對象 (TableAdapters) 區分開來。

發佈了41 篇原創文章 · 獲贊 0 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章