550 likes | 758 Views
ADO.NET 開發高手系列. 台灣微軟資深講師 從 1993 年開始於台灣微軟主講研討會 台灣微軟最有價值專家 兩度當選 MVP 資深電腦圖書作家 擁有 60 本以上的著作 資深技術顧問. 主講人:章立民. ADO.NET 開發高手線上教學課程 第八集 如何建立與使用 DataSet. DataSet 的基本概念( 1/2 ). 將資料快取於資料集 獨立於資料來源之外 緊密整合 XML 結構描述定義資料結構 型別與不具型別的 DataSet 型別和不具型別資料集的資料存取比較
E N D
ADO.NET 開發高手系列 • 台灣微軟資深講師 • 從 1993 年開始於台灣微軟主講研討會 • 台灣微軟最有價值專家 • 兩度當選 MVP • 資深電腦圖書作家 • 擁有 60 本以上的著作 • 資深技術顧問 主講人:章立民
ADO.NET 開發高手線上教學課程第八集如何建立與使用 DataSet
DataSet 的基本概念(1/2) • 將資料快取於資料集 • 獨立於資料來源之外 • 緊密整合 XML • 結構描述定義資料結構 • 型別與不具型別的 DataSet • 型別和不具型別資料集的資料存取比較 • 型別資料集' 存取 Employee 資料表之第一筆資料列的 EmployeeID 欄位Dim s As String = myDataSet.Employee(0).EmployeeID • 不具型別資料集Dim s As String= _ CType(myDataSet.Tables(“Employee”).Rows(0).Item(“EmployeeID”), _ String)
DataSet 的基本概念(2/2) • 資料集的大小寫區分特性 • 填入資料集 • 呼叫資料配接器的 Fill方法。 • 以人工方式填入資料集當中的資料表。 • 呼叫 DataSet 的 ReadXml方法將 XML 文件或資料流讀入資料集。 • 呼叫 DataSet 的 Merge方法來合併(複製)其他資料集的內容。 • 資料列的位置與導覽
資料集的實作流程 • 建立資料集(也就是 DataSet 物件)。 • 在資料集當中建立一或多個資料表。 • 建立資料表間的關聯性連結。 • 於各個資料表中新增、修改、或刪除資料列(DataRow 物件)。 • 呼叫 DataSet 的 GetChanges方法來建立第二個 DataSet(此 DataSet 只包含資料的變更)。 • 將第二個 DataSet 當作引數傳遞給資料配接器的 Update方法。 • 呼叫 DataSet 的 Merge方法將第二個 DataSet 的變更合併到第一個 DataSet。 • 呼叫 DataSet 的 AcceptChanges方法來接受變更,或是呼叫 DataSet 的 RejectChanges方法來取消變更。
如何於資料集當中建立資料表 • 建立 DataTable 物件,然後將 DataTable 物件新增至資料集。 • 透過資料配接器(例如:SqlDataAdapter),將關聯式資料來源內之資料表的資料填入 DataSet 來建立資料表。 • 使用預先定義或推斷的 XML 結構描述建立 DataTable 物件。 • ReadXml • ReadXmlSchema • InferXmlSchema
自行建立 DataTable 物件並新增至資料集 • 關於資料集的資料表集合 • DataTableCollection(資料表集合)會內含 DataSet 的所有 DataTable 物件,可以使用 DataSet 的 Tables屬性來存取它。 • 使用 DataTableCollection 的 Add方法來將 DataTable 物件新增至資料表集合中。 • 使用 DataTableCollection 的 Remove方法從資料表集合中移除指定的 DataTable物件。 • 使用 DataTableCollection 的 Clear方法從資料表集合中移除所有的 DataTable 物件。 • 使用 DataTableCollection 的 Contains方法來判斷特定的資料表是否存在於資料表集合中。
DataTableCollection 之 Add 方法的多載版本(1/3) • Add(ByVal table As DataTable) ' 建立資料集Dim myDataSet As DataSet = _ New DataSet("人事資料集")' 建立資料表Dim limingTable As DataTable = _ New DataTable("章立民工作室")……' 將資料表新增至資料集的資料表集合中myDataSet.Tables.Add(limingTable)
DataTableCollection 之 Add 方法的多載版本(2/3) • Add() As DataTable ' 建立資料集Dim myDataSet As DataSet = _ New DataSet(“人事資料集”)' 於資料集當中建立一個資料表Dim limingTable As DataTable = _myDataSet.Tables.Add()' 設定資料表的名稱limingTable.TableName = "章立民工作室"
DataTableCollection 之 Add 方法的多載版本(3/3) • Add(ByVal name As String) As _ DataTable ' 建立資料集Dim myDataSet As DataSet = _ New DataSet(“人事資料集”)' 於資料集當中建立一個名稱' 為「章立民工作室」的資料表Dim limingTable As DataTable = _myDataSet.Tables.Add("章立民工作室")
存取資料表 • 使用資料表的名稱或索引來存取資料集當中的資料表。例如,假設「章立民工作室」資料表是資料集之資料表集合中的第 1個資料表:myDataSet.Tables(0)-或-myDataSet.Tables("章立民工作室")
程式範例 DemoForm1.vb • 示範如何建立一個資料集、於此資料集當中建立一個資料表、將資料列新增至此資料表、然後再將表單上的 DataGrid 控制項繫結至此資料表。
透過資料配接器在資料集當中建立資料表 • DataAdapter 物件(資料配接器)擔任 DataSet 物件與資料來源間的橋樑。 • IDataAdapter 介面 • IDbDataAdapter 介面 • 請視需要使用一或多個資料配接器。
透過資料配接器在資料集當中建立資料表-實作流程透過資料配接器在資料集當中建立資料表-實作流程 • 使用 SqlDataAdapter 建構函式建立資料配接器物件。 • 將用來提取資料之 SELECT 陳述式或預存程序的名稱指派給資料配接器物件的 SelectCommand屬性。 • 呼叫資料配接器的 Fill方法,以便將所提取的資料列存入資料集當中對應的資料表內。
第一個多載版本的 SqlDataAdapter 建構函式 Dim limingDA As SqlDataAdapter = _ New SqlDataAdapter
第二個多載版本的 SqlDataAdapter 建構函式 ' 建立一個連接字串 Dim strConnection As String = _ "Server=(local)\NetSDK;Database=北風貿易;Integrated Security=SSPI" ' 建立一個查詢命令字串 Dim strSql As String = _ "SELECT 身份證字號,姓名,員工性別,住家地址,出生日期" & _ ",目前薪資,部門,自傳 FROM 飛狐工作室" ' 建立一個資料連接 Dim myConnection As SqlConnection = _ New SqlConnection(strConnection) ' 建立一個 SqlCommand 物件 Dim selectCMD As SqlCommand = _ New SqlCommand(strSql, myConnection) ' 建立一個 SqlDataAdapter 物件 Dim myDA As SqlDataAdapter = New SqlDataAdapter(selectCMD)
第三個多載版本的 SqlDataAdapter 建構函式 ' 建立一個連接字串 Dim strConnection As String = _ "Server=(local)\NetSDK;Database=北風貿易; " & _ " Integrated Security=SSPI" ' 建立一個查詢命令字串 Dim strSql As String = _ "SELECT 身份證字號,姓名,員工性別,住家地址, " & _ "出生日期,目前薪資,部門,自傳 FROM 飛狐工作室" ' 建立一個資料連接 Dim myConnection As SqlConnection = _ New SqlConnection(strConnection) ' 建立一個 SqlDataAdapter 物件 Dim myDA As SqlDataAdapter = _ New SqlDataAdapter(strSql, myConnection)
第四個多載版本的 SqlDataAdapter 建構函式 ' 建立一個連接字串 Dim strConnection As String = _ "Server=(local)\NetSDK;Database=北風貿易; " & _ " Integrated Security=SSPI" ' 建立一個查詢命令字串 Dim strSql As String = _ "SELECT 身份證字號,姓名,員工性別,住家地址, " & _ "出生日期,目前薪資,部門,自傳 FROM 飛狐工作室" ' 建立一個 SqlDataAdapter 物件 Dim myDA As SqlDataAdapter = _ New SqlDataAdapter(strSql, strConnection)
指派 SELECT 陳述式或預存程序(1/3) ' 建立一個連接字串 Dim strConnection As String = _ "Server=(local)\NetSDK;Database=北風貿易;" & _ "Integrated Security=SSPI" ' 建立一個查詢命令字串 Dim strSql As String = _ "SELECT 身份證字號,姓名,員工性別,住家地址, " & _ "出生日期,目前薪資,部門,自傳 FROM 飛狐工作室" ' 建立一個資料連接 Dim myConnection As SqlConnection = _ New SqlConnection(strConnection) ' 建立一個 SqlDataAdapter 物件 Dim myDA As SqlDataAdapter = New SqlDataAdapter ' 建立一個使用SELECT陳述式來提取資料的SqlCommand物件 Dim selectCMD As SqlCommand = _ New SqlCommand(strSql, myConnection) ' 將 SqlCommand 物件指派給 SqlDataAdapter 物件 ' 的 SelectCommand 屬性 myDA.SelectCommand = selectCMD
指派 SELECT 陳述式或預存程序(2/3) ' 建立一個連接字串 Dim strConnection As String = _ "Server=(local)\NetSDK;Database=北風貿易;" & _ "Integrated Security=SSPI" ' 建立一個資料連接 Dim myConnection As SqlConnection = _ New SqlConnection(strConnection) ' 建立一個 SqlDataAdapter 物件 Dim myDA As SqlDataAdapter = New SqlDataAdapter ' 建立一個使用預存程序來提取資料的SqlCommand物件 Dim selectCMD As SqlCommand = _ New SqlCommand("dbo.RetrieveFoxEmployee", myConnection) selectCMD.CommandType = CommandType.StoredProcedure ' 將 SqlCommand 物件指派給 SqlDataAdapter 物件 ' 的 SelectCommand 屬性 myDA.SelectCommand = selectCMD
指派 SELECT 陳述式或預存程序(3/3) myDA.SelectCommand.CommandText = _ "要新套用的Transact-SQL陳述式" & _ "或預存程序的名稱"
呼叫資料配接器的 Fill 方法 • Fill 方法會使用 SelectCommand 屬性所指定的 SELECT 陳述式或預存程序從資料來源擷取資料列,並將所提取的資料列存入 DataSet 內對應的資料表中。 • 如果資料集當中並不存在對應的資料表, Fill 方法會先建立資料表然後再將資料列填入其中。 • 如果對應的資料表已經存在,則 Fill 方法會以目前所提取的資料列來重新整理資料表的資料列,以便使其資料與資料來源中的資料一致。 • Fill 方法會視情況自動開啟與關閉連接。 • 所傳回之各個結果集的資料列分別存放於個別的資料表中。
程式範例 DemoForm2.vb • 示範如何使用 SqlDataAdapter 物件之第二個多載版本的 Fill 方法。
程式範例 DemoForm3.vb • 示範如何使用 SqlDataAdapter 物件之第四個多載版本的 Fill 方法。
程式範例 DemoForm4.vb • 示範如何使用 SqlDataAdapter 物件之第四個多載版本的 Fill 方法將資料列填入一個未隸屬於任何資料集的 DataTable 物件中。
程式範例 DemoForm5.vb • 示範如何將所傳回的多個結果集分別填入資料集當中的各個資料表。
程式範例 DemoForm6.vb • 示範如何使用單一資料配接器來取得單一資料來源的兩個資料表。
程式範例 DemoForm7.vb • 示範使用兩個資料配接器來分別提取單一資料來源之兩個資料表的資料。
程式範例 DemoForm8.vb • 示範如何使用兩個資料配接器分別從兩個異質資料來源各取得一個資料表並建立兩者間的關聯性連結。 • 使用一個資料配接器從 MSDE 的「北風貿易」資料庫取得「產品類別」資料表的資料列並置入資料集當中對應的資料表內,並使用另外一個資料配接器從Access 資料庫檔「北風貿易.mdb」中取得「產品資料」資料表的資料列並置入資料集當中對應的資料表內,然後再於資料集當中建立兩者的關聯性連結。
將現有的條件約束加入 DataSet • Fill 方法能夠重新整理資料列的先決條件: • SQL 陳述式務必與當初用來填入資料表的 SQL 陳述式完全相符。 • 資料表務必擁有主索引鍵。 • 填入 DataSet 時一併加入資料來源上現有的主索引鍵條件約束: • 先呼叫資料配接器的 FillSchema方法,然後才呼叫資料配接器的 Fill方法。 • 先將資料配接器的 MissingSchemaAction屬性設定成 AddWithKey,然後才呼叫資料配接器的 Fill方法。
程式範例 DemoForm9.vb • 示範如何從 MSDE 之「北風貿易」資料庫的「章立民工作室」資料表提取資料,它會沿用來源資料表的結構描述以便使「員工編號」欄位自動成為一個自動編號欄位並且被定義為主索引鍵。在資料集當中建立資料表之後,它還會另行將 UniqueConstraint條件約束套用至「身份證字號」欄位,以確保此欄位不會發生重複的情形。
資料表的前後端對應關係 • 請透過 System.Data.Common 命名空間中的 DataTableMapping物件來完成。 • 使用資料配接器的 TableMappings 屬性來取得 DataTableMappingCollection,並呼叫 DataTableMappingCollection 的 Add 方法來加入一個 DataTableMapping 物件。 • Add(ByVal sourceTable As String, _ ByVal dataSetTable As String) As _DataTableMapping • 簡例:Dim limingMap As DataTableMapping = _ limingDA.TableMappings.Add( _ "章立民工作室", "LimingStudio")
欄位的前後端對應關係 • SelectCommand 屬性的查詢陳述式必須先將查詢結果的欄位名稱設定成所需的名稱。例如:SELECT 員工編號As EmployeeId,身份證字號As Id FROM 章立民工作室 • 使用 DataColumnMapping物件來設定前後端欄位的對應關係,呼叫 DataColumnMappingCollection 的 Add 方法以便於欄位對應集合中加入一個 DataColumnMapping 物件:Add(ByVal sourceColumn As String, _ ByVal dataSetColumn As String) As _ DataColumnMapping例如:limingMap.ColumnMappings.Add("員工編號", "EmployeeId")limingMap.ColumnMappings.Add("身份證字號", "Id")
程式範例 DemoForm10.vb • 示範當前端資料集資料表與後端來源資料表採用不同的資料表和欄位名稱時,該如何建立彼此的對應關係,以便確保當您呼叫資料配接器的 Fill方法時,能夠順利以後端來源資料表的資料列去重新整理前端資料集資料表;反之,當您呼叫資料配接器的 Update方法時,亦能夠順利將前端資料集資料表的異動寫回後端來源資料表。
建立資料表之間的關聯性連結 • 請先建立一個 DataRelation 物件。 • 將步驟 1 所建立的 DataRelation 物件加入資料集的 DataRelationCollection 中。可以透過 DataSet 的 Relations 屬性來存取 DataRelationCollection。 • 套用所需的條件約束。 • 重複步驟 1 至 3 的操作。
程式範例 DemoForm12.vb • 示範如何建立一個一對多介面。在此介面中,父資料表的一方(也就是「產品類別」資料表)會使用各個 TextBox 控制項來顯示各個欄位的內容並透過一組導覽按鈕來加以導覽,當您導覽產品類別的資料列時,與該產品類別相關聯的產品資料便會顯示於 DataGrid 控制項中。
程式範例 DemoForm13.vb • 示範如何建立一個 DataGrid 對 DataGrid 的一對多介面,也就是父資料表(此處為「產品類別」資料表)與子資料表(此處為「產品資料」資料表)皆使用 DataGrid 控制項來顯示其資料列。
程式範例 DemoForm14.vb • 示範如何建立一個一多對介面,特別之處在於,父子雙方各自擁有一組導覽按鈕,具體提高資料的導覽彈性 。
程式範例 DemoForm15.vb • 呼叫 DataRow 物件的 GetChildRows 方法並將 DataRelation 物件傳遞給它,便會傳回一個內含與該筆資料列相關聯之各筆子資料列的 DataRow 物件陣列。 • 呼叫 DataRow 物件的 GetParentRow 方法將 DataRelation 物件傳遞給它,則會傳回與該筆資料列相關聯的父資料列。
建立外部索引鍵條件約束 • 建立兩資料表之間的關聯性連結時就會自動建立並套用下列的條件約束: • 唯一條件約束(Unique Constraint) • 外部索引鍵條件約束(ForeignKey Constraint) • 請透過 DataTable 的 Constraints 屬性來存取 ConstraintCollection(條件約束集合)。 • 將某些多載版本的 DataRelation 建構函式或 DataRelationCollection 之 Add 方法的 createConstraints參數設定成 false,則在建立關聯性連結時就不會自動建立唯一條件約束與外部索引鍵條件約束。
自行建立外部索引鍵條件約束 • 使用 ForeignKeyConstraint 建構函式來建立 ForeignKeyConstraint 物件。 • 設定此 ForeignKeyConstraint 物件的相關屬性。 • 將 ForeignKeyConstraint 物件新增至 DataTable 的 ConstraintCollection 中。
程式範例 DemoForm16.vb • 示範如何建立「客戶」與「訂貨主檔」兩資料表的關聯性連結,並列出所自動建立之唯一條件約束與外部索引鍵條件約束的相關資訊。
程式範例 DemoForm17.vb • 與前一個程式範例 DemoForm16.vb 最主要的差異,是它在建立「客戶」與「訂貨主檔」兩資料表的關聯性連結時會要求不要自動建立條件約束,而會自行替「客戶」資料表(也就是父資料表)建立唯一條件約束並且替「訂貨主檔」資料表(也就是子資料表)建立外部索引鍵條件約束。
如何使用外部索引鍵條件約束 • ForeignKeyConstraint 的 DeleteRule和 UpdateRule屬性定義當使用者嚐試刪除或更新關聯資料表中的資料列時所要採取的動作。 • DeleteRule 和 UpdateRule 屬性的型別都是 Rule列舉型別: • Cascade • SetNull • SetDefault • None • 如果 DataSet 擁有 ForeignKeyConstraints,則當您針對父資料列呼叫 AcceptChanges 或 RejectChanges 方法時,將根據 ForeignKeyConstraint 之 AcceptRejectRule屬性的設定來決定要針對子資料列執行哪些操作,此屬性的型別是 AcceptRejectRule 列舉型別: • Cascade • None • DataSet 的 EnforceConstraints屬性。
取得與設定資料配接器之命令的參數(1/2) • 指派給資料配接器之 SelectCommand屬性的 Transact-SQL 陳述式或預存程序用來從資料來源提取資料以便填入資料集,您必須先設定資料配接器 SelectCommand 屬性,才能呼叫資料配接器的 Fill方法。 • 指派給資料配接器之 InsertCommand、DeleteCommand與 UpdateCommand屬性的 Transact-SQL 陳述式或預存程序則是用來新增、刪除、與更新資料來源中的資料。您也必須先設定資料配接器的 InsertCommand、DeleteCommand 或UpdateCommand 屬性,才能呼叫資料配接器的 Update方法。