ado.net 開發高手系列

47

Upload: jonah

Post on 15-Jan-2016

118 views

Category:

Documents


0 download

DESCRIPTION

ADO.NET 開發高手系列. 台灣微軟資深講師 從 1993 年開始於台灣微軟主講研討會 台灣微軟最有價值專家 兩度當選 MVP 資深電腦圖書作家 擁有 60 本以上的著作 資深技術顧問. 主講人:章立民. ADO.NET 開發高手線上教學課程 第十集 如何更新資料集資料並 寫回資料來源. 兩階段更新. 第一個步驟是以新資訊來更新資料集,通常也就是新增、修改、或刪除資料集當中的資料列。 將變更從資料集寫回原始資料來源。. 於具型別或不具型別資料集的資料表中新增資料列. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: ADO.NET  開發高手系列
Page 2: ADO.NET  開發高手系列

ADO.NET ADO.NET 開發高手系開發高手系列列

台灣微軟資深講師台灣微軟資深講師 從 從 1993 1993 年開始於台灣微軟主講研討年開始於台灣微軟主講研討

會會 台灣微軟最有價值專家台灣微軟最有價值專家

兩度當選 兩度當選 MVPMVP

資深電腦圖書作家資深電腦圖書作家 擁有 擁有 60 60 本以上的著作本以上的著作

資深技術顧問資深技術顧問

主講人:章立民主講人:章立民

Page 3: ADO.NET  開發高手系列

ADO.NET ADO.NET 開發高手線上教學課程開發高手線上教學課程

第十集第十集

如何更新資料集資料並如何更新資料集資料並寫回資料來源寫回資料來源

Page 4: ADO.NET  開發高手系列

兩階段更新兩階段更新1.1. 第一個步驟是以新資訊來更新資料集,通第一個步驟是以新資訊來更新資料集,通

常也就是新增、修改、或刪除資料集當中常也就是新增、修改、或刪除資料集當中的資料列。的資料列。

2.2. 將變更從資料集寫回原始資料來源。將變更從資料集寫回原始資料來源。

Page 5: ADO.NET  開發高手系列

於具型別或不具型別資料集的資料表中新增資料列於具型別或不具型別資料集的資料表中新增資料列1.1. 請宣告一個 請宣告一個 DataRowDataRow 型別的變數。例如:型別的變數。例如:

Dim newRow As DataRowDim newRow As DataRow

2.2. 呼叫資料表的 呼叫資料表的 NewRowNewRow 方法來建立一個 方法來建立一個 DataRow DataRow 物件,並將它物件,並將它指派給步驟 指派給步驟 1 1 所宣告的變數。例如:所宣告的變數。例如:

newRow = _newRow = _ myDataSet.Tables(" myDataSet.Tables(" 章立民工作室章立民工作室 ").NewRow()").NewRow()

3.3. 使用欄位的名稱或索引(從 使用欄位的名稱或索引(從 0 0 開始起算)來將資料值指派給新資料開始起算)來將資料值指派給新資料列的各個欄位。例如:列的各個欄位。例如:

newRow("newRow(" 姓名姓名 ") = "") = " 章立民章立民 ""

-或--或-

newRow(0) = "newRow(0) = " 章立民章立民 ""

4.4. 呼叫資料列集合的 呼叫資料列集合的 AddAdd 方法將已指派資料值的 方法將已指派資料值的 DataRow DataRow 物件新物件新增至資料列集合中。例如:增至資料列集合中。例如:

myDataSet.Tables("myDataSet.Tables(" 章立民工作室章立民工作室 ").Rows.Add(newRow)").Rows.Add(newRow)

Page 6: ADO.NET  開發高手系列

於具型別資料集的資料表中新於具型別資料集的資料表中新增資料列增資料列 在設計階段將在設計階段將資料表名稱資料表名稱公開為公開為 DataSetDataSet

物件的物件的屬性屬性並將並將欄位名稱欄位名稱公開為公開為 DataRowDataRow 物件的物件的屬性屬性。例如:。例如:

Dim newRow As DataRow = _Dim newRow As DataRow = _ ds ds 章立民工作室章立民工作室 1.1. 章立民工作室章立民工作室 .NewRow().NewRow()newRow.newRow. 姓名姓名 = "= " 章立民章立民 ""newRow.newRow. 出生日期出生日期 = #1/1/1980#= #1/1/1980#dsds 章立民工作室章立民工作室 1.1. 章立民工作室章立民工作室 .Rows.Add(n.Rows.Add(newRow)ewRow)

Page 7: ADO.NET  開發高手系列

於具型別或不具型別資料集的資料表中編輯資料列於具型別或不具型別資料集的資料表中編輯資料列 將資料值指派給特定資料列的特定欄位。將資料值指派給特定資料列的特定欄位。 請透過索引(從 請透過索引(從 0 0 開始起算)來取得資料列集合中特定開始起算)來取得資料列集合中特定

的資料列。的資料列。 假設「姓名」欄位是資料表的第 假設「姓名」欄位是資料表的第 3 3 個欄位,而您想要將個欄位,而您想要將

第 第 1 1 筆資料列之「姓名」欄位的內容修改成 “章立民” :筆資料列之「姓名」欄位的內容修改成 “章立民” :

myDataSet.Tables("myDataSet.Tables(" 章立民工作室章立民工作室 ").Rows(").Rows(00)()("" 姓姓名名 "" ) = " ) = " 章立民章立民 " " -或--或-myDataSet.Tables("myDataSet.Tables(" 章立民工作室章立民工作室 " ).Rows(" ).Rows(00)()(33) =) = " " 章立民章立民 " " -或--或-myDataSet.Tables("myDataSet.Tables(" 章立民工作室章立民工作室 " ).Rows(" ).Rows(00).).ItemItem("(" 姓名姓名 " )" ) = " = " 章立民章立民 " " -或--或-myDataSet.Tables("myDataSet.Tables(" 章立民工作室章立民工作室 ").Rows(").Rows(00).).Item(3)Item(3) = "= " 章立民章立民 " "

將表單上的控制項繫結至資料表的欄位,然後透過控制項將表單上的控制項繫結至資料表的欄位,然後透過控制項來編輯欄位資料。來編輯欄位資料。

Page 8: ADO.NET  開發高手系列

於具型別資料集的資料表中編於具型別資料集的資料表中編輯資料列輯資料列 在設計階段將在設計階段將資料表名稱資料表名稱公開為 公開為 DataSetDataSet

物件的物件的屬性屬性並將並將欄位名稱欄位名稱公開為 公開為 DataRoDataRoww 物件的物件的屬性屬性。例如:。例如:

dsds 章立民工作室章立民工作室 1.1. 章立民工作室章立民工作室 (1)(1).. 姓姓名名 = "= " 章立民章立民 " " dsds 章立民工作室章立民工作室 1.1. 章立民工作室章立民工作室 (1)(1).. 出出生日期生日期 = #1/1/1980# = #1/1/1980#

Page 9: ADO.NET  開發高手系列

如何於資料集資料表中刪除資料列如何於資料集資料表中刪除資料列 呼叫所要刪除之 呼叫所要刪除之 DataRow DataRow 物件的 物件的 DeleteDelete

方法。方法。 Delete Delete 方法只會將資料列標示成刪除並使方法只會將資料列標示成刪除並使

其 其 RowStateRowState 屬性成為 屬性成為 DeletedDeleted 。。 直到您呼叫 直到您呼叫 AcceptChangesAcceptChanges 方法時才會方法時才會

真正將其移除並使其 真正將其移除並使其 RowStateRowState 屬性成為 屬性成為 DetachedDetached 。 。

如果資料列的 如果資料列的 RowStateRowState 屬性為 屬性為 AddedAdded ,,則只要您呼叫此資料列物件的 則只要您呼叫此資料列物件的 Delete Delete 方方法,資料列就會立刻從資料表中移除而成法,資料列就會立刻從資料表中移除而成為 為 DetachedDetached 狀態。 狀態。

DataRowCollection DataRowCollection 的 的 Count Count 屬性會將屬性會將被標示為刪除的資料列一併計算在內。 被標示為刪除的資料列一併計算在內。

Page 10: ADO.NET  開發高手系列

資料更新事件資料更新事件 具型別事件:具型別事件:

dataTableNameRowChangingdataTableNameRowChanging dataTableNameRowChangeddataTableNameRowChanged dataTableNameRowDeletingdataTableNameRowDeleting dataTableNameRowDeleteddataTableNameRowDeleted

資料更新事件:資料更新事件: ColumnChangingColumnChanging ColumnChangedColumnChanged RowChangingRowChanging RowChangedRowChanged RowDeletingRowDeleting RowDeletedRowDeleted

Page 11: ADO.NET  開發高手系列

暫時停止更新條件約束暫時停止更新條件約束

1.1. 變更資料列中的資料之前,先呼叫 變更資料列中的資料之前,先呼叫 DataRDataRowow 物件的 物件的 BeginEditBeginEdit 方法。方法。

2.2. 開始更新這個資料列。開始更新這個資料列。3.3. 呼叫 呼叫 EndEditEndEdit 方法來認可對資料列的變方法來認可對資料列的變

更,然後重新啟用條件約束檢查。更,然後重新啟用條件約束檢查。4.4. 如果需要的話,呼叫資料列的 如果需要的話,呼叫資料列的 CancelEditCancelEdit

方法來捨棄資料列的變更。 方法來捨棄資料列的變更。

Page 12: ADO.NET  開發高手系列

合併資料集(合併資料集( 1/21/2 ) ) 來源資料集中的新資料列會被加入目標資來源資料集中的新資料列會被加入目標資

料集當中。料集當中。 來源資料集當中的額外欄位也會被加入目來源資料集當中的額外欄位也會被加入目

標資料集當中。標資料集當中。 適合的作業模式:適合的作業模式:

擁有一個本機資料集,並且從其他應用程式或 擁有一個本機資料集,並且從其他應用程式或 XML Web Service XML Web Service 之類的元件中取得第二個之類的元件中取得第二個資料集,而且第二個資料集內含要新增至第一資料集,而且第二個資料集內含要新增至第一個資料集的資料列。個資料集的資料列。

您的應用程式要從兩個不同的元件取得資料集,您的應用程式要從兩個不同的元件取得資料集,但是需要在單一資料集中使用資料。但是需要在單一資料集中使用資料。

Page 13: ADO.NET  開發高手系列

合併資料集(合併資料集( 2/22/2 )) 呼叫資料集的 呼叫資料集的 MergeMerge 方法。方法。 合併具有大量相似結構描述的兩個 合併具有大量相似結構描述的兩個 DataSet DataSet 物物

件。件。 藉由將 藉由將 Merge Merge 方法的 方法的 missingSchemaActionmissingSchemaAction

參數設定成 參數設定成 MissingSchemaAction.AddMissingSchemaAction.Add 來將來將結構描述項目加入目標資料集。 結構描述項目加入目標資料集。

DataRowState DataRowState 屬性為 屬性為 UnchangedUnchanged 、、 ModifieModified d 或 或 Deleted Deleted 的所有來源資料列會使用相同的的所有來源資料列會使用相同的主索引鍵值來對應至目標資料列。 主索引鍵值來對應至目標資料列。

DataRowState DataRowState 屬性為 屬性為 Added Added 的來源資料列,的來源資料列,則會使用與新來源資料列相同的主索引鍵值來對則會使用與新來源資料列相同的主索引鍵值來對應至新目標資料列。 應至新目標資料列。

在合併期間,會停用條件約束。在合併期間,會停用條件約束。

Page 14: ADO.NET  開發高手系列

Merge Merge 方法的多載版本方法的多載版本Merge(ByVal rows() As DataRow)Merge(ByVal rows() As DataRow)

Merge(ByVal dataSet As DataSet)Merge(ByVal dataSet As DataSet)

Merge(ByVal table As DataTable)Merge(ByVal table As DataTable)

Merge(ByVal dataSet As DataSet, _ Merge(ByVal dataSet As DataSet, _ ByVal preserveChanges As Boolean) ByVal preserveChanges As Boolean)

Merge(ByVal rows() As DataRow, _ Merge(ByVal rows() As DataRow, _ ByVal preserveChanges As Boolean, _ ByVal preserveChanges As Boolean, _ ByVal missingSchemaAction _ ByVal missingSchemaAction _ As MissingSchemaAction) As MissingSchemaAction)

Merge(ByVal dataSet As DataSet, _ Merge(ByVal dataSet As DataSet, _ ByVal preserveChanges As Boolean, _ ByVal preserveChanges As Boolean, _ ByVal missingSchemaAction As MissingSchemaAction) ByVal missingSchemaAction As MissingSchemaAction)

Merge(ByVal table As DataTable, _ Merge(ByVal table As DataTable, _ ByVal preserveChanges As Boolean, _ ByVal preserveChanges As Boolean, _ ByVal missingSchemaAction As MissingSchemaAction) ByVal missingSchemaAction As MissingSchemaAction)

Page 15: ADO.NET  開發高手系列

認可資料集中的變更認可資料集中的變更 如果您要將資料集當中的資料異動寫回資如果您要將資料集當中的資料異動寫回資

料來源,則請在成功執行資料配接器的 料來源,則請在成功執行資料配接器的 UUpdate pdate 方法之後再呼叫資料集的 方法之後再呼叫資料集的 AcceptCAcceptChanges hanges 方法。方法。

如果您要從其他資料集複製資訊並接著認如果您要從其他資料集複製資訊並接著認可變更,請先呼叫資料集的 可變更,請先呼叫資料集的 Merge Merge 方法,方法,然後再呼叫資料集的 然後再呼叫資料集的 AcceptChanges AcceptChanges 方方法。 法。

Page 16: ADO.NET  開發高手系列

檢查變更的資料列檢查變更的資料列 當變更資料集當中的資料列時,關於這些變更的當變更資料集當中的資料列時,關於這些變更的

資訊會被儲存,直到您認可它們為止。資訊會被儲存,直到您認可它們為止。 每一筆資料列中之變更的追蹤方式: 每一筆資料列中之變更的追蹤方式:

透過 透過 DataRow DataRow 物件的 物件的 RowState RowState 屬性來保屬性來保有變更的類型。有變更的類型。

使用資料集替變更資料列所維護的多個版本。 使用資料集替變更資料列所維護的多個版本。 使用資料集的 使用資料集的 HasChanges HasChanges 方法來判斷資料集方法來判斷資料集

是否內含變更的資料列。是否內含變更的資料列。

HasChanges HasChanges 方法的多載版本方法的多載版本HasChanges()HasChanges()

HasChanges(ByVal rowStates _HasChanges(ByVal rowStates _ As DataRowState) As DataRowState)

Page 17: ADO.NET  開發高手系列

擷取變更的資料列擷取變更的資料列 呼叫資料集或資料表的 呼叫資料集或資料表的 GetChangesGetChanges 方方

法會傳回只包含已變更資料列的新資料集法會傳回只包含已變更資料列的新資料集或資料表。 或資料表。

GetChanges GetChanges 方法的多載版本方法的多載版本GetChanges()GetChanges()

GetChanges(ByVal GetChanges(ByVal rowStatesrowStates _ _ As As DataRowStateDataRowState) )

Dim myChangedRowsDS As DataSetDim myChangedRowsDS As DataSet

myChangedRowsDS = myChangedRowsDS = ds.GetChanges()ds.GetChanges()

Dim myChangedRowsDS As DataSetDim myChangedRowsDS As DataSet

myChangedRowsDS = myChangedRowsDS = ds.GetChanges(ds.GetChanges(DataRowState.AddedDataRowState.Added))

Page 18: ADO.NET  開發高手系列

於資料集當中搜尋個別的資料列於資料集當中搜尋個別的資料列 DataRowCollection DataRowCollection 物件的 物件的 FindFind 方法可方法可

以透過資料表的以透過資料表的主索引鍵主索引鍵來搜尋資料列。 來搜尋資料列。 Find Find 方法的多載版本方法的多載版本

Find(ByVal Find(ByVal keykey As Object) As DataRow As Object) As DataRow

Find(ByVal Find(ByVal keyskeys()() As Object) As DataRow As Object) As DataRow

' ' 搜尋主索引鍵值為 搜尋主索引鍵值為 M123321000 M123321000 的資料列的資料列Dim foundRow As DataRow = Dim foundRow As DataRow = myTable.Rows.FimyTable.Rows.Fi

nd("M123321000")nd("M123321000")

' ' 顯示出所找到之資料列的第一個欄位內容顯示出所找到之資料列的第一個欄位內容If Not (If Not (foundRow Is NothingfoundRow Is Nothing) Then) Then

Console.WriteLine(foundRow(1).ToString())Console.WriteLine(foundRow(1).ToString())

End If End If

Dim foundRow As DataRowDim foundRow As DataRow

' ' 建立一個主索引鍵值陣列來加以搜尋建立一個主索引鍵值陣列來加以搜尋Dim findTheseVals(2) As ObjectDim findTheseVals(2) As Object

' ' 將陣列的各個元素設定成所要搜尋的資料值將陣列的各個元素設定成所要搜尋的資料值findTheseVals(0) = "findTheseVals(0) = " 章章 ""

findTheseVals(1) = "findTheseVals(1) = " 立民立民 ""

findTheseVals(2) = "findTheseVals(2) = " 中和中和 ""

foundRow = foundRow = myTable.Rows.Find(findTheseVals)myTable.Rows.Find(findTheseVals)

' ' 顯示出所找到之資料列的第一個欄位內容顯示出所找到之資料列的第一個欄位內容If Not (If Not (foundRow Is NothingfoundRow Is Nothing) Then) Then

Console.WriteLine(foundRow(1).ToString())Console.WriteLine(foundRow(1).ToString())

End If End If

Page 19: ADO.NET  開發高手系列

Find Find 方法使用注意事項方法使用注意事項 務必已經替資料表建立主索引鍵,否則將務必已經替資料表建立主索引鍵,否則將擲回 擲回 MissingPrimaryKeyException MissingPrimaryKeyException 例例外狀況。外狀況。

使用限制:使用限制: Find Find 方法不會區分大小寫。方法不會區分大小寫。 不能於 不能於 Find Find 方法中使用萬用字元。以下陳述方法中使用萬用字元。以下陳述

式表示尋找主索引鍵為 式表示尋找主索引鍵為 Ch% Ch% 的資料列:的資料列:

myDataRow = _myDataRow = _ myDataTable.Rows.Find(" myDataTable.Rows.Find("Ch%Ch%")")

Page 20: ADO.NET  開發高手系列

如何取得資料列的特定版本(如何取得資料列的特定版本( 1/41/4 ))

只有在編輯資料列之後以及呼叫 只有在編輯資料列之後以及呼叫 AcceptCAcceptChanges hanges 方法之前,資料列才會存在不同方法之前,資料列才會存在不同版本。版本。

在 在 ColumnChanging ColumnChanging 和 和 ColumnChangColumnChanged ed 事件期間檢視資料列的不同版本以便進事件期間檢視資料列的不同版本以便進行驗證。行驗證。

如果暫時停用條件約束,透過迴圈來循序如果暫時停用條件約束,透過迴圈來循序處理 處理 Columns Columns 集合並比較不同的集合並比較不同的 DataRDataRowVersionowVersion 值。 值。

Page 21: ADO.NET  開發高手系列

如何取得資料列的特定版本(如何取得資料列的特定版本( 2/42/4 ))

DataRow(ByVal DataRow(ByVal columncolumn As As DataColumnDataColumn, _ , _ ByVal ByVal versionversion As As DataRowVersionDataRowVersion) As ) As ObjectObject

DataRow(ByVal DataRow(ByVal columnNamecolumnName As As StringString, _ , _ ByVal ByVal versionversion As As DataRowVersionDataRowVersion) As ) As ObjectObject

DataRow(ByVal DataRow(ByVal columnIndexcolumnIndex As As IntegerInteger, _ , _ ByVal ByVal versionversion As As DataRowVersionDataRowVersion) As ) As ObjectObject

Page 22: ADO.NET  開發高手系列

如何取得資料列的特定版本(如何取得資料列的特定版本( 3/43/4 ))Dim firstRow As DataRow = _Dim firstRow As DataRow = _

ds.Tables(" ds.Tables(" 章立民工作室章立民工作室 ").Rows(").Rows(00))

' ' 編輯「姓名」欄位的內容編輯「姓名」欄位的內容firstRow("firstRow(" 姓名姓名 ") = "") = " 章立民“章立民“

' ' 取得第一筆資料列之「姓名」欄位的 取得第一筆資料列之「姓名」欄位的 Current Current 版版本本

Dim CurrentName As String = _Dim CurrentName As String = _ firstRow(" firstRow(" 姓名姓名 ", ", DataRowVersion.CurrentDataRowVersion.Current))

' ' 取得第一筆資料列之「姓名」欄位的 取得第一筆資料列之「姓名」欄位的 Original Original 版版本本

Dim OriginalName As String = _Dim OriginalName As String = _ firstRow(" firstRow(" 姓名姓名 ", ", DataRowVersion.OriginalDataRowVersion.Original) )

Page 23: ADO.NET  開發高手系列

如何取得資料列的特定版本(如何取得資料列的特定版本( 4/44/4 ))

呼叫 呼叫 HasVersionHasVersion 方法並且將 方法並且將 DataRowDataRowVersion Version 當作引數傳遞給它,以便檢測 當作引數傳遞給它,以便檢測 DDataRow ataRow 物件是否具有特定的資料列版本。物件是否具有特定的資料列版本。例如:例如:

DataRow.HasVersion( _DataRow.HasVersion( _ DataRowVersion.Original) DataRowVersion.Original)

Page 24: ADO.NET  開發高手系列

資料集當中的資料驗證(資料集當中的資料驗證( 1/1/22 )) 透過主索引鍵與唯一條件約束來進行唯一透過主索引鍵與唯一條件約束來進行唯一

性驗證。性驗證。 透過外部索引鍵條件約束來確保資料參考透過外部索引鍵條件約束來確保資料參考完整性。完整性。

使用欄位的相關屬性來輔助完成資料驗證使用欄位的相關屬性來輔助完成資料驗證作業。作業。

自行替應用程式撰寫資料驗證邏輯的程式自行替應用程式撰寫資料驗證邏輯的程式碼,以便在欄位和資料列變更事件期間檢碼,以便在欄位和資料列變更事件期間檢查資料。查資料。

Page 25: ADO.NET  開發高手系列

資料集當中的資料驗證(資料集當中的資料驗證( 2/2/22 )) 資料列發生變更時將引發的 資料列發生變更時將引發的 DataTable DataTable 物物

件的下列事件:件的下列事件: ColumnChanging ColumnChanging 與 與 ColumnChanged ColumnChanged 事事

件。件。 RowChanging RowChanging 與 與 RowChanged RowChanged 事件。事件。

每次變更一個欄位時將會依序引發四個事每次變更一個欄位時將會依序引發四個事件:件: ColumnChangingColumnChanging ColumnChangedColumnChanged RowChangingRowChanging RowChangedRowChanged

BeginEdit BeginEdit 與 與 EndEdit EndEdit 方法的影響。方法的影響。

Page 26: ADO.NET  開發高手系列

在欄位變更期間驗證資料在欄位變更期間驗證資料1.1. 替資料表的 替資料表的 ColumnChanging ColumnChanging 事件建立事件建立

事件處理常式。事件處理常式。2.2. 在事件處理常式中檢查 在事件處理常式中檢查 ProposedValue ProposedValue 和 和 Row Row 屬性來傳回建議值和原始值。例屬性來傳回建議值和原始值。例如:如:Dim newValue As String = CType(Dim newValue As String = CType(e.ProposedValuee.ProposedValue, String), String)Dim origvalue As String = CType(Dim origvalue As String = CType(e.Row(e.Columne.Row(e.Column), String) ), String)

3.3. 如果要取得正被變更之欄位的資訊,請檢如果要取得正被變更之欄位的資訊,請檢查傳遞至事件處理常式的 查傳遞至事件處理常式的 Column Column 屬性。屬性。例如:例如:Dim colDataType As String = e.Dim colDataType As String = e.ColumnColumn.DataType.ToString().DataType.ToString()Dim colName As String = e.Dim colName As String = e.ColumnColumn.ColumnName .ColumnName

4.4. 如果要拒絕變更,請擲回例外狀況。如果要拒絕變更,請擲回例外狀況。

Private Sub dt_ColumnChanging(ByVal sender As _Private Sub dt_ColumnChanging(ByVal sender As _ Object, ByVal e As _Object, ByVal e As _ System.Data.DataColumnChangeEventArgs) _System.Data.DataColumnChangeEventArgs) _ Handles dt.ColumnChangingHandles dt.ColumnChanging

Dim Dim newvaluenewvalue As Integer = _ As Integer = _ CType(CType(e.ProposedValuee.ProposedValue, Integer), Integer) If If newvalue < 10000newvalue < 10000 Then Then MessageBox.Show(newvalue.ToString() & _MessageBox.Show(newvalue.ToString() & _ " " 不能小於 不能小於 10000")10000") Throw New Exception(newvalue.ToString() & _Throw New Exception(newvalue.ToString() & _ " " 不能小於 不能小於 10000")10000") End IfEnd IfEnd SubEnd Sub

Page 27: ADO.NET  開發高手系列

在資料列變更期間驗證資料在資料列變更期間驗證資料1.1. 首先,請替資料表的 首先,請替資料表的 RowChangingRowChanging 事事

件建立事件處理常式。件建立事件處理常式。2.2. 在事件處理常式中透過擷取各個欄位的 在事件處理常式中透過擷取各個欄位的 PrPr

oposed oposed 版本來取得資料列的變更:版本來取得資料列的變更:

newName = CType(e.Row("newName = CType(e.Row(" 客戶名稱客戶名稱 ", ", __ DataRowVersion.ProposedDataRowVersion.Proposed), String) ), String)

3.3. oldName = CType(e.Row("oldName = CType(e.Row(" 客戶名稱客戶名稱 ", _", _ DataRowVersion.OriginalDataRowVersion.Original), String) ), String)

4.4. 執行驗證。執行驗證。

Page 28: ADO.NET  開發高手系列

資料列變更期間驗證資料簡例資料列變更期間驗證資料簡例Private Sub dtCustomers_Private Sub dtCustomers_CustomersRowChangingCustomersRowChanging( _( _ ByVal sender As System.Object, _ByVal sender As System.Object, _ ByVal e As ds.CustomersRowChangeEvent) _ByVal e As ds.CustomersRowChangeEvent) _ Handles Handles dtCustomers.CustomersRowChangingdtCustomers.CustomersRowChanging

Dim original As String = ""Dim original As String = "" Dim proposed As String = ""Dim proposed As String = "" If e.Row.HasVersion(If e.Row.HasVersion(DataRowVersion.OriginalDataRowVersion.Original) Then) Then original = _original = _ CType(e.Row("CType(e.Row("客戶編號客戶編號 ", ", DataRowVersion.OriginalDataRowVersion.Original), String)), String) ElseElse original = "“original = "“ End IfEnd If proposed = e.Row.proposed = e.Row. 客戶編號客戶編號

If original <> "" ThenIf original <> "" Then If proposed = "" ThenIf proposed = "" Then Throw New Exception("Throw New Exception(" 客戶編號不能是空的。客戶編號不能是空的。 ")") End IfEnd If End IfEnd IfEnd Sub End Sub

Page 29: ADO.NET  開發高手系列

將資料集變更寫回資料來源將資料集變更寫回資料來源 必須先設定資料配接器的必須先設定資料配接器的 InsertCommandInsertCommand 、、 UU

pdateCommand pdateCommand 與 與 DeleteCommand DeleteCommand 屬性,屬性,然後再呼叫資料配接器的 然後再呼叫資料配接器的 Update Update 方法。方法。

Update Update 方法會循序處理資料表中的每一筆資料方法會循序處理資料表中的每一筆資料列,並根據資料列的 列,並根據資料列的 RowState RowState 來執行適當的來執行適當的陳述式(也就是 陳述式(也就是 INSERTINSERT 、、 UPDATE UPDATE 或 或 DELEDELETE TE 陳述式)。 陳述式)。 這些陳述式並不會被當作一個批次來執行,而是每一這些陳述式並不會被當作一個批次來執行,而是每一

筆資料列個別執行其更新。筆資料列個別執行其更新。 欲控制不同類型之陳述式的執行順序,必須先取得新欲控制不同類型之陳述式的執行順序,必須先取得新

增、修改、與刪除的資料列,然後依所需的順序更新增、修改、與刪除的資料列,然後依所需的順序更新之。之。

UpdatedRowSource UpdatedRowSource 屬性。屬性。 OnRowUpdated OnRowUpdated 事件。事件。

Page 30: ADO.NET  開發高手系列

使用 使用 Update Update 方法時的執行順序方法時的執行順序1.1. DataRow DataRow 中的值會被移至參數值。中的值會被移至參數值。2.2. OnRowUpdating OnRowUpdating 事件會被引發。事件會被引發。3.3. 執行命令。執行命令。4.4. 如果命令設定為 如果命令設定為 FirstReturnedRecordFirstReturnedRecord ,,

則傳回的第一個結果會置入 則傳回的第一個結果會置入 DataRow DataRow 中。中。5.5. 如果有輸出參數,它們會被置入 如果有輸出參數,它們會被置入 DataRoDataRo

w w 中。 中。 6.6. OnRowUpdated OnRowUpdated 事件會被引發。事件會被引發。7.7. AcceptChanges AcceptChanges 方法會被呼叫。方法會被呼叫。

Page 31: ADO.NET  開發高手系列

Update Update 方法的使用注意事項(方法的使用注意事項( 1/1/44 )) 應該在 應該在 Try...Catch Try...Catch 區塊內呼叫資料配接器的 區塊內呼叫資料配接器的 UU

pdate pdate 方法。方法。 如果您希望在遇到錯誤時繼續更新作業而不要產如果您希望在遇到錯誤時繼續更新作業而不要產

生例外狀況,請在呼叫 生例外狀況,請在呼叫 Update Update 方法之前,先將方法之前,先將資料配接器的 資料配接器的 ContinueUpdateOnErrorContinueUpdateOnError 屬性屬性設定成設定成 TrueTrue 。。 可在資料配接器的 可在資料配接器的 RowUpdatedRowUpdated 事件中,以每一筆事件中,以每一筆

資料列為基礎來回應錯誤。資料列為基礎來回應錯誤。 可將 可將 RowUpdatedEventArgsRowUpdatedEventArgs 的 的 StatusStatus 屬性設定屬性設定

成 成 ContinueContinue 。 。 如何控制新增、修改、與刪除作業的處理順序如何控制新增、修改、與刪除作業的處理順序

使用 使用 DataTable DataTable 的 的 SelectSelect 方法來傳回特定資料列方法來傳回特定資料列狀態的 狀態的 DataRow DataRow 物件陣列,並傳遞給資料配接器的 物件陣列,並傳遞給資料配接器的 Update Update 方法以便只處理這些資料列。 方法以便只處理這些資料列。

Page 32: ADO.NET  開發高手系列

Update Update 方法的使用注意事項(方法的使用注意事項( 2/2/44 ))Dim myTable As DataTable = ds.Tables("Dim myTable As DataTable = ds.Tables(" 客戶客戶 ")")

' ' 先處理刪除的資料列先處理刪除的資料列myDA.myDA.UpdateUpdate( _( _ myTable.Select(Nothing, Nothing,myTable.Select(Nothing, Nothing, DataViewRowState.DeletedDataViewRowState.Deleted))))

' ' 接著處理已更新的資料列接著處理已更新的資料列myDA.myDA.UpdateUpdate( _( _ myTable.Select(Nothing, Nothing,myTable.Select(Nothing, Nothing, DataViewRowState.ModifiedCurrentDataViewRowState.ModifiedCurrent))))

' ' 最後再處理已新增的資料列最後再處理已新增的資料列myDA.myDA.UpdateUpdate( _( _ myTable.Select(Nothing, Nothing,myTable.Select(Nothing, Nothing, DataViewRowState.AddedDataViewRowState.Added)) ))

Page 33: ADO.NET  開發高手系列

Update Update 方法的使用注意事項(方法的使用注意事項( 3/3/44 )) 必須分別呼叫每一個資料表所對應之資料必須分別呼叫每一個資料表所對應之資料配接器的 配接器的 Update Update 方法來個別更新它們。方法來個別更新它們。

如果資料表之間具有關聯性連結:如果資料表之間具有關聯性連結:1.1. 子資料表:刪除資料列。子資料表:刪除資料列。2.2. 父資料表:新增、修改、與刪除資料列。父資料表:新增、修改、與刪除資料列。3.3. 子資料表:新增與修改資料列。 子資料表:新增與修改資料列。

為什麼要在更新資料來源之後去重新填入為什麼要在更新資料來源之後去重新填入資料集?資料集? 反應出其他使用者的變更。反應出其他使用者的變更。 擷取由資料庫所計算的欄位值。擷取由資料庫所計算的欄位值。 為了能夠在並行控制中使用時間戳記。為了能夠在並行控制中使用時間戳記。

Page 34: ADO.NET  開發高手系列

Update Update 方法的使用注意事項(方法的使用注意事項( 4/4/44 )) 當資料來源的資料表擁有自動編號欄位時當資料來源的資料表擁有自動編號欄位時

在 在 DataSet DataSet 內建立 內建立 AutoIncrementStep AutoIncrementStep 為 為 -1-1 以及 以及 AutoIncrementSeed AutoIncrementSeed 為 為 00 的攔位。的攔位。

請確定資料來源所產生的自動遞增值從 請確定資料來源所產生的自動遞增值從 11 開開始,並以始,並以正值正值來遞增。 來遞增。

可以使用 可以使用 Guid Guid 型別的欄位來取代自動遞增型別的欄位來取代自動遞增欄位。 欄位。

Page 35: ADO.NET  開發高手系列

如何回應資料庫更新錯誤如何回應資料庫更新錯誤1.1. 替 替 RowUpdated RowUpdated 事件建立事件處理常式。事件建立事件處理常式。2.2. 檢查 檢查 RowUpdated RowUpdated 事件的 事件的 Status Status 屬性。屬性。

如果有錯誤,此值將會是 如果有錯誤,此值將會是 ErrorsOccurreErrorsOccurredd 。。

3.3. 如果您要控制更新是否繼續,請將 如果您要控制更新是否繼續,請將 Status Status 屬性設定為 屬性設定為 UpdateStatus UpdateStatus 列舉型別的某列舉型別的某一個成員。一個成員。

4.4. 您可以視需要在事件物件中設定目前資料您可以視需要在事件物件中設定目前資料列的 列的 RowError RowError 屬性。屬性。

Page 36: ADO.NET  開發高手系列

ADO.NET ADO.NET 的並行控制的並行控制 「並行控制」(「並行控制」( Concurrency ControlConcurrency Control ))

是用來辨識和解決當有多位使用者同時更是用來辨識和解決當有多位使用者同時更新相同的資料時所衍生的相關問題,以便新相同的資料時所衍生的相關問題,以便確保資料的一致性。 。 確保資料的一致性。 。

Page 37: ADO.NET  開發高手系列

並行控制的類型並行控制的類型 封閉式並行控制(封閉式並行控制( Pessimistic Concurrency CPessimistic Concurrency C

ontrolontrol )) 適用強況:適用強況:

相同資料列被爭用的機率非常高時…相同資料列被爭用的機率非常高時… 不允許在交易期間變更資料…不允許在交易期間變更資料…

中斷連接的架構無法使用封閉式並行控制。中斷連接的架構無法使用封閉式並行控制。 「樂觀並行控制」(「樂觀並行控制」( Optimistic Concurrency Optimistic Concurrency

ControlControl )) 已變更之資料列的原始版本會與資料庫中的現有資料已變更之資料列的原始版本會與資料庫中的現有資料

列比較,以便檢查資料庫中的資料列是否已被其他使列比較,以便檢查資料庫中的資料列是否已被其他使用者變更過,如果發現兩者有所不同,則更新就會失用者變更過,如果發現兩者有所不同,則更新就會失敗並發生並行錯誤。 敗並發生並行錯誤。

「後進先寫入」(「後進先寫入」( Last In WinsLast In Wins ))

Page 38: ADO.NET  開發高手系列

ADO.NET ADO.NET 與 與 VS.NET VS.NET 的並行控制的並行控制

採用樂觀並行控制。採用樂觀並行控制。 必須自行撰寫程式邏輯來解決並行違規的必須自行撰寫程式邏輯來解決並行違規的問題。問題。

判斷是否發生變更:判斷是否發生變更: 版本編號方法。版本編號方法。 儲存所有值方法。 儲存所有值方法。

Page 39: ADO.NET  開發高手系列

版本編號方法版本編號方法 要被更新的資料列必須擁有一個內含日期要被更新的資料列必須擁有一個內含日期

時間戳記或版本編號的欄位。時間戳記或版本編號的欄位。 時間戳記相符時才更新:時間戳記相符時才更新:

UPDATE myTable UPDATE myTable SET Column1 = @newvalue1, SET Column1 = @newvalue1, Column2 = @newvalue2 Column2 = @newvalue2 WHERE WHERE DateTimeStamp = @origDateTimeStampDateTimeStamp = @origDateTimeStamp

版本編號相符時才更新:版本編號相符時才更新:UPDATE myTable UPDATE myTable SET Column1 = @newvalue1, SET Column1 = @newvalue1, Column2 = @newvalue2 Column2 = @newvalue2 WHERE WHERE RowVersion = @origRowVersionValueRowVersion = @origRowVersionValue

Page 40: ADO.NET  開發高手系列

儲存所有值方法(儲存所有值方法( 1/21/2 )) 讀取資料列時取得所有欄位的複本。讀取資料列時取得所有欄位的複本。 DataSet DataSet 物件會維護每一個被修改之資料物件會維護每一個被修改之資料

列的兩個版本:一為原始版本(原本從資列的兩個版本:一為原始版本(原本從資料來源讀取的版本),另一個則是使用者料來源讀取的版本),另一個則是使用者更新過的修改版本。 更新過的修改版本。

當嚐試將資料列寫回資料來源時,會將資當嚐試將資料列寫回資料來源時,會將資料列中的原始值與資料來源中的資料列加料列中的原始值與資料來源中的資料列加以比較。如果兩者相符,成功寫回。以比較。如果兩者相符,成功寫回。

Page 41: ADO.NET  開發高手系列

儲存所有值方法(儲存所有值方法( 2/22/2 ))UPDATE UPDATE 客戶客戶 SET SET 客戶編號 客戶編號 = = @currCustomerID@currCustomerID, , 公司名稱 公司名稱 = = @currCompanyName@currCompanyName,, 連絡人 連絡人 = = @currContactName@currContactName, , 連絡人職稱 連絡人職稱 = = @currContactTitle@currContactTitle,, 地址 地址 = = @currAddress@currAddress, , 城市 城市 = = @currCity@currCity, , 郵遞區號 郵遞區號 = = @currPostalCode@currPostalCode,, 電話 電話 = = @currPhone@currPhone, , 傳真電話 傳真電話 = = @currFax@currFax WHERE (WHERE (客戶編號 客戶編號 = = @origCustomerID@origCustomerID) AND ) AND ((地址地址 = = @origAddress@origAddress OR OR @origAddress@origAddress IS NULL AND IS NULL AND 地址 地址 IS NULL)IS NULL) ANDAND ((城市 城市 = = @origCity@origCity OR OR @origCity@origCity IS NULL AND IS NULL AND 城市 城市 IS NULL)IS NULL) AND AND (( 公司名稱公司名稱 = = @origCompanyName@origCompanyName OR OR @origCompanyName@origCompanyName IS NULL AND IS NULL AND 公司名稱 公司名稱 IS NULL) IS NULL) AND AND ((連絡人 連絡人 = = @origContactName@origContactName OR OR @origContactName@origContactName IS NULL AND IS NULL AND 連絡人連絡人 IS NULL)IS NULL) ANDAND ((連絡人職稱 連絡人職稱 = = @origContactTitle@origContactTitle OR OR @origContactTitle@origContactTitle IS NULL AND IS NULL AND 連絡人職稱 連絡人職稱 IS NULL)IS NULL) ANDAND ((傳真電話 傳真電話 = = @origFax@origFax OR OR @origFax@origFax IS NULL AND IS NULL AND傳真電話 傳真電話 IS NULL)IS NULL) ANDAND (( 電話 電話 = = @origPhone@origPhone OR OR @origPhone@origPhone IS NULL AND IS NULL AND 電話 電話 IS NULL)IS NULL) ANDAND ((郵遞區號 郵遞區號 = = @origPostalCode@origPostalCode OR OR @origPostalCode@origPostalCode IS NULL AND IS NULL AND 郵遞區號 郵遞區號 IS NULL);IS NULL);SELECT SELECT 客戶編號客戶編號 , , 公司名稱公司名稱 , , 連絡人連絡人 , , 連絡人職稱連絡人職稱 , , 地址地址 , , 城市城市 , , 郵遞區號郵遞區號 , , 電話電話 , , 傳真電話 傳真電話 FROFRO

M M 客戶客戶 WHERE (WHERE (客戶編號 客戶編號 = = @currCustomerID@currCustomerID) )

Page 42: ADO.NET  開發高手系列

使用動態 使用動態 SQL SQL 實作樂觀並行實作樂觀並行

Page 43: ADO.NET  開發高手系列

使用預存程序實作樂觀並行使用預存程序實作樂觀並行

Page 44: ADO.NET  開發高手系列

如何處理並行錯誤如何處理並行錯誤 使用 使用 DBConcurrencyException DBConcurrencyException 物件來物件來解決並行違規所引發的問題。 解決並行違規所引發的問題。

如果受影響的資料列數目等於如果受影響的資料列數目等於零零則由 則由 DatDataAdapter aAdapter 在更新作業期間擲回的例外狀在更新作業期間擲回的例外狀況況 (Exception)(Exception) 。。DBConcurrencyException DBConcurrencyException 物件的屬性 物件的屬性 屬性屬性 說明說明

MessageMessage 取得描述目前例外狀況的訊息。取得描述目前例外狀況的訊息。RowRow 取得造成 取得造成 DBConcurrencyExceptiDBConcurrencyExcepti

on on 的 的 DataRowDataRow 。。

Source Source 取得或設定造成錯誤的應用程式或取得或設定造成錯誤的應用程式或物件的名稱。物件的名稱。

Page 45: ADO.NET  開發高手系列

並行違規範例並行違規範例 DemoForm4.vbDemoForm4.vb

展示如何將資料集當中的變更寫回資料來源。展示如何將資料集當中的變更寫回資料來源。 具備完善的機制來處置並行違規的狀況。具備完善的機制來處置並行違規的狀況。

Page 46: ADO.NET  開發高手系列

並行違規範例設計步驟並行違規範例設計步驟

Page 47: ADO.NET  開發高手系列

結束結束 別忘了定期上下列網站:別忘了定期上下列網站:

MSDN MSDN 中文網站中文網站http://www.microsoft.com/taiwan/msdn/http://www.microsoft.com/taiwan/msdn/

微軟技術社群網站微軟技術社群網站http://www.microsoft.com/taiwan/communityhttp://www.microsoft.com/taiwan/community

微軟最有價值專家 微軟最有價值專家 MVPMVPMicrosoft Most Valuable ProfessionalsMicrosoft Most Valuable Professionals 微軟爲什麼要選拔 微軟爲什麼要選拔 MVP MVP 誰可以申請為微軟最有價值專家(誰可以申請為微軟最有價值專家( MVPMVP ) )