利用TableAdapter更新數據庫

將數據保存在數據集中

保存數據就是將應用程序中的已更改數據保存回原始數據存儲區(通常是關係數據庫,如 SQL Server)的過程。

因爲數據集是有效的數據緩存(數據在內存中的副本),所以將信息寫入初始數據源的進程與在數據集中修改數據的進程是分開的。 通過調用 TableAdapter 的一個 Update 方法,或調用 TableAdapter 的一個 DBDirect 方法,可以將數據集中的已更新數據發送回數據庫。

有關將數據集中的更改發送回數據集的更多信息,請參見如何:使用 TableAdapter 更新數據如何:將數據集更改保存到數據庫中

Visual Studio 提供了一個 TableAdapterManager 組件,該組件可幫助您保存相關表中的數據。 此組件可確保按照數據庫中定義的外鍵約束來以正確的順序執行保存。 有關更多信息,請參見分層更新概述

有關修改數據集中的數據的信息,請參見 在應用程序中編輯數據

兩步更新

通過數據集更新數據源是一個包含兩個步驟的過程。 第一步是使用新信息(新記錄、已更改的記錄或已刪除的記錄)更新數據集。 如果您的應用程序只與數據集有關(例如在更新數據集後,將其發送給另一個應用程序,由它對數據集執行進一步處理),那麼您就完成了更新。

 提示

在 Windows 窗體中,數據綁定結構負責將更改從數據綁定控件發送到數據集,您不必用自己的代碼顯式更新數據集。 有關更多信息,請參見 Windows 窗體數據綁定

如果您正在更新數據源(如數據庫),第二步則是將更改從數據集發送到初始數據源。 也就是說,更新數據集的過程不會同時將更改直接寫入基礎數據源,所以您必須顯式執行第二步。 爲了完成這一步驟,您通常會調用曾用來填充數據集的同一個 TableAdapter(或數據適配器)的 Update 方法(雖然您也可以使用不同的適配器,例如爲了將數據從一個數據源移動到另一個數據源或更新多個數據源)。

兩步更新過程和 DataRowVersion 在成功更新中的作用

Visual Basic 數據集更新

在結構上,數據集使數據可以作爲多組集合來使用。 數據集包含表的集合。 表包含行的集合。 表公開爲 DataSet 對象的集合,記錄在 DataTable 對象的 Rows 集合中可用。 您可以通過使用基集合方法操作這些集合來對數據集中的數據進行更改,但是如果您要更新基礎數據源,則必須使用專用於數據集修改的方法。

例如,要從數據表中移除一個記錄,可以調用該表的 Rows 集合的 RemoveAt 方法,它會從數據集中實際刪除該記錄。 如果您只是將數據集用作數據的結構化存儲區,而不考慮將更改信息傳送到另一個應用程序,那麼以這種方式操作集合就是一種可以接受的數據集更新方式。

但是,如果您要將更改發送到數據源或另一個應用程序,則需要維護有關每次更新的更改信息(即元數據)。 隨後,在將更改發送到數據源或應用程序時,該過程將使用它所需的信息來查找和更新適當的記錄。 例如,如果刪除數據集中的一個記錄,則必須在數據集中維護有關該刪除記錄的信息。 這樣,當調用 TableAdapter 的 DeleteCommand 時,就會有足夠的歷史信息來查找數據源中的初始記錄,從而可將其刪除。 有關更多信息,請參見下面的“維護有關更改的信息”。

合併數據集

您可以通過合併來更新數據集的內容,合併就是將稱作“源”的數據集的內容複製到調用數據集(稱作“目標”數據集)中。 當合並數據集時,源數據集中的新記錄將添加到目標數據集中。 另外,源數據集中額外的列也會添加到目標數據集中。 當您具有一個本地數據集然後又從另一個應用程序或組件(如 XML Web services)獲得另外一個數據集時,合併數據集就會特別有用。 在需要集成來自多個數據集中的數據時,它也十分有用。

合併數據集時,還可以傳遞一個可選的布爾型參數 (preserveChanges),它指示 Merge 方法是否在目標數據集中保留現有的修改。 由於數據集維護記錄的多個版本,所以務必要記住所合併的是記錄的多個版本。 下表闡釋了將要合併的兩個數據集中的一個記錄:

合併數據集

DataRowVersion

目標數據集

源數據集

原始

James Wilson

James C. Wilson

當前

Jim Wilson

James C. Wilson

在 preserveChanges=false targetDataset.Merge(sourceDataset) 的情況下,對上表調用 Merge 方法將產生以下結果:

合併數據集

DataRowVersion

目標數據集

源數據集

原始

James C. Wilson

James C. Wilson

當前

James C. Wilson

James C. Wilson

在 preserveChanges = true targetDataset.Merge(sourceDataset, true) 的情況下調用 Merge 方法將產生以下結果:

表 3

DataRowVersion

目標數據集

源數據集

原始

James C. Wilson

James C. Wilson

當前

Jim Wilson

James C. Wilson

 警告

在 preserveChanges = true 的情況下,如果對目標數據集中的記錄調用 RejectChanges 方法,它將還原爲源數據集中的初始數據。 這意味着如果您要用目標數據集更新初始數據源,則可能無法找到要更新的初始行。 但是,通過用數據源中已更新的記錄填充另一個數據集,然後執行防止併發衝突的合併,可以防止出現併發衝突。 (當另一個用戶在數據集被填充後修改數據源中的記錄時,會發生併發衝突。)有關更多信息,請參見 ADO.NET 中的併發控制

更新約束

要對現有的數據行進行更改,可以在個別列中添加或更新數據。 如果數據集包含約束(例如外鍵或不可爲 null 的約束),那麼當您更新記錄時(在更新完一列之後,但在開始更新下一列之前),記錄可能會暫時處於錯誤狀態。

爲了避免這種早產的約束衝突,可以暫時掛起更新約束。 這可達到兩個目的:

  • 防止在更新完一列後,開始更新另一列之前引發錯誤。

  • 暫停引發某些更新事件(常用於衝突的事件)。

完成更新後,可以重新啓用約束檢查,約束檢查還重新啓用更新事件並引發它們。

 提示

在 Windows 窗體中,內置在數據網格中的數據綁定結構會暫停約束檢查,直到焦點移出行外爲止,因此您不必顯式調用 BeginEditEndEdit 或 CancelEdit 方法。

當對數據集調用 Merge 方法時,將自動禁用約束。 當合並完成後,如果數據集上有任何無法啓用的約束,則引發 ConstraintException。 在這種情況下,EnforceConstraints 屬性將設置爲 false,並且在將 EnforceConstraints 屬性重新設置爲 true 之前,必須解決所有約束衝突。

完成更新後,可以重新啓用約束檢查,約束檢查還重新啓用更新事件並引發它們。

有關暫停事件的更多信息,請參見如何:在填充數據集時關閉約束

數據集更新錯誤

當更新數據集中的記錄時,可能出現錯誤。 例如,您可能在無意中將數據類型錯誤、太長或具有某些其他完整性問題的數據寫入一個列中。 此外,您可能擁有應用程序特定的驗證檢查,它們可在更新事件的任何階段引發自定義的錯誤。 有關更多信息,請參見 驗證數據集中的數據

維護有關更改的信息

有關數據集中更改的信息可以通過以下兩種方式來進行維護:通過對行進行標記,指示該行是否已更改 (RowState);以及通過保留記錄的多個副本 (DataRowVersion)。 利用這些更改信息,進程可以確定數據集中有哪些更改,並且可以將適當的更新發送到數據源。

RowState 屬性

DataRow 對象的 RowState 屬性是一個值,它提供有關特定數據行狀態的信息。

下表詳細說明 DataRowState 枚舉的可能值:

ROWSTATE 屬性

DataRowState 值

說明

Added

該行已作爲一項添加到 DataRowCollection。 (處於這種狀態的行不具有相應的初始版本,因爲在最近一次調用 AcceptChanges 方法時它尚不存在)。

Deleted

已使用 DataRow 對象的 Delete 刪除了該行。

Detached

已創建該行,但它不是任何 DataRowCollection 的一部分。 在 DataRow 對象剛創建之後但在添加到集合之前,或者如果該對象已從集合中移除,它將處於這種狀態。

Modified

該行中的列值已通過某種方式更改。

Unchanged

自上一次調用 AcceptChanges 之後,該行未更改。

DataRowVersion 枚舉

數據集維護記錄的多個版本。 DataRow 對象的 DataRowVersion 枚舉是一個值,它可用於返回 DataRow 對象的特定版本。

下表詳細說明 DataRowVersion 枚舉的可能值:

DATAROWVERSION 枚舉

DataRowVersion 值

說明

Current

記錄的當前版本包含自上次調用 AcceptChanges 後對記錄執行的所有修改。 如果該行已被刪除,則沒有當前版本。

Default

記錄的默認值,如數據集架構或數據源所定義的一樣。

Original

記錄的初始版本是在數據集中最後一次提交更改時記錄的副本。 實際上,它通常是從數據源中讀取的記錄版本。

Proposed

更新過程當中(即在調用 BeginEdit 方法和調用 EndEdit 方法之間)臨時可用的記錄的建議版本。 通常在事件(例如 RowChanging)處理程序中訪問記錄的建議版本。 調用 CancelEdit 方法將撤消更改並刪除數據行的建議版本。

當更新信息傳送到數據源時,初始版本和當前版本十分有用。 通常,當更新被髮送到數據源時,數據庫的新信息處於記錄的當前版本中。 來自初始版本的信息用於查找要更新的記錄。 例如,在更改了記錄主鍵的情況下,爲了將該更改更新到數據源,必須通過某種方式在數據源中查找適當的記錄。 如果不存在初始版本,則很可能會將該記錄追加到數據源,這不僅會導致一項額外的多餘記錄,而且還會導致一條不準確並且已過期的記錄。 這兩個版本也用於併發控制;您可以將初始版本與數據源中的記錄進行比較,以確定該記錄自加載到數據集之後是否經過更改。 有關更多信息,請參見 ADO.NET 中的併發控制

當您需要在將更改實際提交到數據集之前執行驗證時,可以使用建議版本。

即使記錄已更改,也不總會有該行的初始版本或當前版本。 當您將新行插入表中時,沒有初始版本,只有當前版本。 同樣,如果通過調用表的 Delete 方法刪除一行,則只有初始版本,沒有當前版本。

您可以通過查詢數據行的 HasVersion 方法,來測試記錄的某個特定版本是否存在。 當請求列的值時,通過將 DataRowVersion 枚舉值作爲可選參數進行傳遞,可以訪問記錄的任何一個版本。

獲取已更改的記錄

通常,不會對數據集中的每個記錄進行更新。 例如,用戶可能正在處理一個顯示很多記錄的 Windows 窗體 DataGridView 控件。 但是,用戶可能只更新了幾個記錄,刪除了一個記錄,並插入了一個新記錄。 數據集和數據表提供了一種只返回已修改行的方法 (GetChanges)。

可以使用數據表的 GetChanges 方法 (GetChanges) 或數據集本身的該方法 (GetChanges) 來創建已更改記錄的子集。 如果對數據表調用該方法,它將返回只包含已更改記錄的數據表副本。 同樣,如果對數據集調用該方法,將獲得一個新的數據集,其中只包含已更改的記錄。 GetChanges 本身將返回所有已更改的記錄。 然而,通過將所需的 DataRowState 作爲參數傳遞給 GetChanges 方法,則可以指定所需的更改記錄子集:新添加的記錄、標記爲刪除的記錄、分離的記錄或已修改的記錄。

當需要將記錄發送給另一個組件進行處理時,獲取已更改記錄的子集非常有用。 通過只獲取該組件所需的記錄而不是發送整個數據集,可以降低與其他組件通信的系統開銷。 有關更多信息,請參見如何:檢索已更改的行

提交數據集中的更改

當在數據集中做出更改時,即設置了所更改行的 RowState 屬性。 此時將建立並維護記錄的初始版本和當前版本,並通過 RowVersion 屬性供您使用。 要將適當的更新發送給數據源,需要使用存儲在這些屬性中表示更改的元數據。

如果更改反映了數據源的當前狀態,則不再需要維護該信息。 通常,數據集及其數據源在以下兩個時間是同步的:

  • 剛剛將信息加載到數據集之後,例如從數據源讀取數據時。

  • 將更改從數據集發送到數據源之後(但不是在這之前,因爲您可能丟失將更改發送到數據庫所需的更改信息)。

通過調用 AcceptChanges 方法,可以將掛起的更改提交到數據集。 通常,在以下時間將在應用程序中調用 AcceptChanges

  • 在加載數據集之後。 如果通過調用 TableAdapter 的 Fill 方法來加載數據集,該適配器將自動爲您提交更改。 但是,如果通過將另一個數據集合併到其中來加載數據集,則必須手動提交更改。

     提示

    通過將適配器的 AcceptChangesDuringFill 屬性設置爲 false,可以防止在調用 Fill 方法時適配器自動提交更改。 如果它設置爲 false,則在填充過程中插入的每行的 RowState 都將設置爲 Added

  • 在將數據集更改發送到另一個進程(例如 XML Web service)之後。

     警告

    以這種方法提交更改會清除所有更改信息。 在執行應用程序確信已知在數據集中作出何種更改的任何操作之前,請不要提交更改。

該方法完成以下操作:

AcceptChanges 方法可以在三個級別上使用。 可以對 DataRow 對象調用該方法,它只提交該行的更改。 還可以對 DataTable 對象調用該方法,以提交表中所有行的更改,或者對 DataSet 對象調用該方法,以提交數據集中所有表的所有記錄的所有掛起的更改。

下表基於對何種對象調用該方法說明所提交的更改。

表 6

方法

結果

DataRow.AcceptChanges

只提交特定行的更改

DataTable.AcceptChanges

提交特定表中所有行的更改

DataSet.AcceptChanges

提交數據集中所有表的所有行的更改

 提示

如果通過調用 TableAdapter 的 Fill 方法加載數據集,則無需顯式接受更改;默認情況下,Fill 方法會在填充完數據表後調用 AcceptChanges 方法。

相關方法 RejectChanges 撤消更改的影響,方法是將記錄的 Original 版本複製回 Current 版本中,並將每個記錄的 RowState 設置回 Unchanged

數據驗證

爲了驗證應用程序中的數據符合它將傳遞到的進程的要求,通常需要添加驗證。 這可能會涉及到檢查用戶在窗體中的輸入是否正確,驗證另一個應用程序向您的應用程序發送的數據,甚至檢查在您的組件中計算的信息是否符合數據源約束和應用程序要求。

您可以通過多種方法驗證數據:

  • 在業務層,將代碼添加到應用程序中以便驗證數據。 數據集是可以執行此操作的一個位置。 數據集提供了後端驗證的某些優點,例如能夠在更改列和行值時驗證更改。 有關更多信息,請參見 驗證數據集中的數據

  • 在表示層,向窗體添加驗證。 有關更多信息,請參見Windows 窗體中的用戶輸入驗證

  • 在數據後端,將數據發送到數據源(例如數據庫)並允許它接受或拒絕該數據。 如果您正在使用一個數據庫,而該數據庫具有複雜的功能來驗證數據並提供錯誤信息,則這將是一種實用的方法,因爲無論數據來自何處,您都可以對數據進行驗證。 但是,它可能不適合應用程序特定的驗證的需要。 另外,根據您的應用程序如何解決由後端引發的驗證錯誤,讓數據源驗證數據可能導致大量到數據源的往返過程。

    表 7
    安全說明安全說明

    在使用將 CommandType 屬性設置爲 Text 的數據命令時,將從客戶端發送的信息傳遞到數據庫前請仔細檢查該信息。 惡意用戶可能會嘗試發送(插入)修改過的或其他 SQL 語句,以獲得未經授權的訪問或破壞數據庫。 在將用戶輸入內容傳輸到數據庫之前,應始終確認這些信息是有效的;如果可能的話,請始終使用參數化查詢或存儲過程,這是最佳做法。 有關更多信息,請參見腳本侵入概述

當在數據集中作出更改之後,可以將更改傳遞給數據源。 完成此操作時最常用的方法是調用 TableAdapter(或數據適配器)的 Update 方法。 該方法依次通過數據表中的每個記錄,確定需要什麼類型的更新(更新、插入或刪除),然後執行適當的命令(如果有)。

如何將更新傳遞給數據源

爲了闡釋如何進行更新,假設您的應用程序使用一個包含單個數據表的數據集。 該應用程序從數據庫中獲取兩行。 在檢索之後,內存中的數據表類似於下面這樣:

(RowState)     CustomerID   Name             Status
(Unchanged)    c200         Robert Lyon      Good
(Unchanged)    c400         Nancy Buchanan    Pending

應用程序將 Nancy Buchanan 的狀態更改爲“Preferred”。作爲這種更改的結果,該行的 RowState 屬性的值從 Unchanged 更改爲 Modified。 第一行的 RowState 屬性的值保持爲 Unchanged。 數據表現在類似於下面這樣:

(RowState)     CustomerID   Name             Status
(Unchanged)    c200         Robert Lyon      Good
(Modified)     c400         Nancy Buchanan    Preferred

應用程序現在調用 Update 方法,將數據集傳送給數據庫。 該方法依次檢查每一行。 對於第一行,由於它從最初取自數據庫後未經過更改,所以該方法不向數據庫傳送任何 SQL 語句。

但是對於第二行,Update 方法將自動調用適當的數據命令並將其傳送給數據庫。 SQL 語句的具體語法取決於基礎數據存儲區所支持的 SQL 語言分支。 但所傳送的 SQL 語句具有下列值得注意的一般特徵:

  • 所傳送的 SQL 語句是一個 UPDATE 語句。 因爲 RowState 屬性的值爲 Modified,所以適配器知道應使用 UPDATE 語句。

  • 所傳送的 SQL 語句包含一個 WHERE 子句,它指示 UPDATE 語句的目標是 CustomerID = 'c400' 的行。 由於 CustomerID 是目標表的主鍵,SELECT 語句的這一部分會將目標行與其他所有行區分開來。 WHERE 子句的信息是從記錄 (DataRowVersion.Original) 的初始版本導出的,以備在識別行所需的值已被更改的情況下使用。

  • 所傳送的 SQL 語句包含 SET 子句,用以設置已修改列的新值。

     提示

    如果 TableAdapter 的 UpdateCommand 屬性已設置爲存儲過程的名稱,則適配器不會構造 SQL 語句。 而是使用傳入的適當參數調用存儲過程。

傳遞參數

數據庫中要更新的記錄的值通常使用參數來進行傳遞。 當 TableAdapter 的 Update 方法執行 UPDATE 語句時,它需要填寫參數值。 它從 Parameters 集合中爲適當的數據命令(在本例中是 TableAdapter 中的 UpdateCommand 對象)獲取這些值。

如果您已使用 Visual Studio 工具生成數據適配器,則 UpdateCommand 對象將包含一個參數集合,這些參數對應於語句中的每個參數佔位符。

每個參數的 SqlParameter.SourceColumn 屬性都指向數據表中的一個列。 例如,au_id 和 Original_au_id 參數的 SourceColumn 屬性設置爲包含作者 ID 的數據表中的任意一列。 當適配器的 Update 方法運行時,它從所更新的記錄中讀取作者 ID 列,並將值填充到語句中。

在 UPDATE 語句中,您需要指定新值(將寫入記錄的值)和舊值(以便在數據庫中查找要更新的記錄)。 因此,每個值都有兩個參數:一個用於 SET 子句,另一個則用於 WHERE 子句。 兩個參數都從所更新的記錄中讀取數據,但根據參數的 SqlParameter.SourceVersion 屬性,它們會獲取該列值的不同版本。 SET 子句的參數獲取當前版本,而 WHERE 子句的參數獲取初始版本。

 提示

您還可以自己在代碼中設置 Parameters 集合中的值,這通常是在數據適配器的 RowChanging 事件的事件處理程序中進行的。

更新相關表

如果數據集包含多個表,則必須通過分別調用每個數據適配器的 Update 方法來逐個更新這些表。 如果這些表具有父子關係,很可能需要以特定的順序將更新發送到數據庫。 常見的情況是已經將父記錄和相關子記錄添加到數據集中,例如一個新的客戶記錄及一個或多個相關的訂單記錄。 如果數據庫本身強制關係完整性規則,那麼當您在創建父記錄之前將新的子記錄發送到數據庫時,數據庫將引發錯誤。

相反,如果刪除數據集中的相關記錄,您通常需要以相反的順序發送更新:先發送子表,然後發送父表。 否則,數據庫很可能引發錯誤,因爲引用完整性規則將阻止您在相關子記錄仍存在的情況下刪除父記錄。

爲相關表發送更新的一般規則遵循以下順序:

  1. 子表:刪除記錄。

  2. 父表:插入、更新和刪除記錄。

  3. 子表:插入和更新記錄。

  4. 有關更多信息,請參見演練:將數據保存到數據庫(多個表)

併發控制

由於數據集與數據源是分開的,您並不持有數據源中記錄上的鎖。 因此,如果要更新數據庫,並且如果維護併發控制對應用程序來說十分重要,則必須協調數據集中的記錄和數據庫中的記錄。 例如,您可能發現數據庫中的記錄在上一次填充數據集之後已經更改。 在這種情況下,必須執行適合於應用程序的邏輯來指定如何處理數據庫記錄或數據集中已更改的記錄。 有關更多信息,請參見 ADO.NET 中的併發控制

請參見

任務

如何:使用 TableAdapter 更新數據

概念

TableAdapter 概述

在 Visual Studio 中將控件綁定到數據

其他資源

Visual Studio 的數據應用程序概述

連接到 Visual Studio 中的數據

準備應用程序以接收數據

將數據獲取到應用程序

在應用程序中編輯數據

驗證數據

保存數據


 

如何:將數據集更改保存到數據庫中

在修改並驗證了數據集中的數據後,可能需要將更新後的數據發回數據庫。 爲了向數據庫發送修改的數據,您可調用 TableAdapter 或數據適配器的 Update 方法。 此適配器的 Update 方法將更新單個數據表並根據該表中每個數據行的 RowState 執行正確的命令(INSERT、UPDATE 或 DELETE)。

將數據保存在相關表中時,Visual Studio 提供的 TableAdapterManager 組件有助於根據在數據庫中定義的外鍵約束以正確的順序執行保存。 有關更多信息,請參見分層更新概述

 提示

由於嘗試使用數據集的內容更新數據源可能會導致錯誤,因此應將調用該適配器的 Update 方法的代碼放置在 try/catch 塊的內部。

根據您的業務需要,更新數據源的確切過程可能會有所不同,但是您的應用程序應該包括以下步驟:

  1. 執行 try/catch 塊中嘗試將更新發送到數據庫的代碼。

  2. 如果捕獲到異常,則找到引發錯誤的數據行。 有關更多信息,請參見如何:定位出錯的行

  3. 協調數據行中的問題(在可能的情況下以編程的方式進行,或者將無效的行顯示給用戶進行修改),然後重新嘗試更新(HasErrors 屬性,GetErrors 方法)。

將數據保存到數據庫

調用 TableAdapter 或數據適配器的 Update 方法,將包含要寫入值的數據表的名稱傳遞給數據庫。 有關將單個數據表中的數據保存回數據庫的更多信息,請參見演練:將數據保存到數據庫(單個表)

通過 TableAdapter 用數據集更新數據庫

  • 在 try/catch 塊中包含 TableAdapter.Update 方法。 下面的示例演示如何嘗試用 NorthwindDataSet 中的 Customers 表的內容進行更新。

    C#
    try
    {
        this.Validate();
        this.customersBindingSource.EndEdit();
        this.customersTableAdapter.Update(this.northwindDataSet.Customers);
        MessageBox.Show("Update successful");
    }
    catch (System.Exception ex)
    {
        MessageBox.Show("Update failed");
    }
    

使用數據適配器用數據集更新數據庫

  • 在 try/catch 塊中包含 DataAdapter.Update 方法。 下面的示例演示如何嘗試用 DataSet1 中的 Table1 的內容對數據源進行更新。

    C#
    try
    {
        SqlDataAdapter1.Update(Dataset1.Tables["Table1"]);
    }
    catch (Exception e)
    {
        // Error during Update, add code to locate error, reconcile 
        // and try to update again.
    }
    

更新數據集中的兩個相關表

當更新數據集中的相關表時,務必要以正確的順序進行更新,以減小違反引用完整性約束的可能性。 命令執行的順序也將遵循數據集中 DataRowCollection 的索引的順序。 爲了防止引發數據完整性錯誤,最佳做法是按照下面的順序更新數據庫:

  1. 子表:刪除記錄。

  2. 父表:插入、更新和刪除記錄。

  3. 子表:插入和更新記錄。

有關從多個表保存數據的詳細信息,請參見演練:將數據保存到數據庫(多個表)

如果要更新兩個或更多相關表,則應將所有更新邏輯包括在一個事務內。 事務是指一個過程,它首先確保對數據庫的所有相關更改均可成功完成,然後再提交更改。 有關更多信息,請參見事務和併發 (ADO.NET)

使用 TableAdapter 更新兩個相關表

  1. 創建三個臨時 DataTable 以保存不同的記錄。

  2. 從 try/catch 塊中爲每個子行集調用 Update 方法。 如果出現更新錯誤,建議的操作過程則將分支並解除錯誤。

  3. 將更改從數據集提交到數據庫。

  4. 處置臨時數據表以釋放資源。

    C#
    void UpdateDB()
    {
        NorthwindDataSet.OrdersDataTable deletedChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Deleted);
    
        NorthwindDataSet.OrdersDataTable newChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Added);
    
        NorthwindDataSet.OrdersDataTable modifiedChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Modified);
    
        try
        {
            if (deletedChildRecords != null)
            {
                ordersTableAdapter.Update(deletedChildRecords);
            }
    
            customersTableAdapter.Update(northwindDataSet.Customers);
    
            if (newChildRecords != null)
            {
                ordersTableAdapter.Update(newChildRecords);
            }
    
            if (modifiedChildRecords != null)
            {
                ordersTableAdapter.Update(modifiedChildRecords);
            }
    
            northwindDataSet.AcceptChanges();
        }
    
        catch (Exception ex)
        {
            MessageBox.Show("An error occurred during the update process");
            // Add code to handle error here.
        }
    
        finally
        {
            if (deletedChildRecords != null)
            {
                deletedChildRecords.Dispose();
            }
            if (newChildRecords != null)
            {
                newChildRecords.Dispose();
            }
            if (modifiedChildRecords != null)
            {
                modifiedChildRecords.Dispose();
            }
        }
    }
    

使用數據適配器更新兩個相關表

  • 調用每個數據適配器的 Update 方法。

    下面的示例顯示如何用包含相關表的數據集更新數據源。 爲了遵循上面的順序,將創建三個臨時 DataTable 來保存不同的記錄。 然後,將在 try/catch 塊中對每個子行集調用 Update 方法。 如果出現更新錯誤,建議的操作過程則將分支並解除錯誤。 然後,數據集提交更改。 最後,處置臨時數據表以釋放資源。

    C#
    void UpdateDB()
    {
        System.Data.DataTable DeletedChildRecords = 
            dsNorthwind1.Orders.GetChanges(System.Data.DataRowState.Deleted);
    
        System.Data.DataTable NewChildRecords = 
            dsNorthwind1.Orders.GetChanges(System.Data.DataRowState.Added);
    
        System.Data.DataTable ModifiedChildRecords = 
            dsNorthwind1.Orders.GetChanges(System.Data.DataRowState.Modified);
    
        try
        {
            if (DeletedChildRecords != null)
            {
                daOrders.Update(DeletedChildRecords);
            }
            if (NewChildRecords != null)
            {
                daOrders.Update(NewChildRecords);
            }
            if (ModifiedChildRecords != null)
            {
                daOrders.Update(ModifiedChildRecords);
            }
    
            dsNorthwind1.AcceptChanges();
        }
    
        catch (Exception ex)
        {
            // Update error, resolve and try again
        }
    
        finally
        {
            if (DeletedChildRecords != null)
            {
                DeletedChildRecords.Dispose();
            }
            if (NewChildRecords != null)
            {
                NewChildRecords.Dispose();
            }
            if (ModifiedChildRecords != null)
            {
                ModifiedChildRecords.Dispose();
            }
        }
    }
    

請參見

概念

數據應用程序開發中的新增功能

在 Visual Studio 中將 Windows 窗體控件綁定到數據

在 Visual Studio 中將控件綁定到數據

其他資源

數據演練

連接到 Visual Studio 中的數據

準備應用程序以接收數據

將數據獲取到應用程序

在應用程序中編輯數據

驗證數據

保存數據


 

如何:使用 TableAdapter 更新數據

更新:2011 年 4 月

在修改並驗證了數據集中的數據後,可能需要將更新後的數據發回數據庫。 要將修改後的數據發送到數據庫,需要調用 TableAdapter 的 Update 方法。 此適配器的 Update 方法將更新單個數據表並根據該表中每個數據行的 RowState 執行正確的命令(INSERT、UPDATE 或 DELETE)。 當您將數據保存在相關表中時,Visual Studio 提供的 TableAdapterManager 組件有助於根據在數據庫中定義的外鍵約束以正確的順序執行保存。 有關更多信息,請參見分層更新概述

 提示

由於嘗試使用數據集的內容更新數據源可能會導致錯誤,因此應將調用該適配器的 Update 方法的代碼放入 try/catch 塊內。

根據不同的業務需求,更新數據源的確切過程可能會有所不同,但是您的應用程序應該包括以下步驟:

  1. 在 try/catch 塊中調用適配器的 Update 方法。

  2. 如果捕獲到異常,則找到引發錯誤的數據行。 有關更多信息,請參見如何:定位出錯的行

  3. 解決數據行中的問題(在可能的情況下以編程方式進行,或者將無效的行提供給用戶進行修改),然後重新嘗試更新(HasErrorsGetErrors)。

將數據保存到數據庫

調用 TableAdapter 的 Update 方法,傳遞數據表的名稱,該數據表包含要寫入數據庫的值。

將數據保存到數據庫
重要說明重要事項

使用本地數據庫(如 .mdf 文件)時,不能將文件的“複製到輸出”屬性設置爲“始終複製”。 如果該屬性設置爲“始終複製”,則生成項目時,文件將覆蓋對本地數據庫所做的任何更改。 若要更正此問題,請在解決方案資源管理器中右擊該文件,單擊“屬性”,並更改“複製到輸出”的值。

使用 TableAdapter 更新具有數據集的數據庫

  • 在 try/catch 塊中包含適配器的 Update 方法。 下面的示例演示如何嘗試用 NorthwindDataSet 中的 Customers 表的內容從 try/catch 塊內部執行更新。

    C#
    try
    {
        this.Validate();
        this.customersBindingSource.EndEdit();
        this.customersTableAdapter.Update(this.northwindDataSet.Customers);
        MessageBox.Show("Update successful");
    }
    catch (System.Exception ex)
    {
        MessageBox.Show("Update failed");
    }
    

使用 TableAdapter 更新數據集中的兩個相關表

更新數據集中的相關表時,爲了減小違反引用完整性約束的可能性,必須以正確的順序進行更新。 命令執行的順序也將遵循數據集中 DataRowCollection 的索引的順序。 爲了防止引發數據完整性錯誤,最佳做法是按照下面的順序更新數據庫:

  1. 子表:刪除記錄。

  2. 父表:插入、更新和刪除記錄。

  3. 子表:插入和更新記錄。

     提示

    如果要更新兩個或更多相關表,應將所有更新邏輯包括在一個事務內。 事務是指一個過程,它在提交任何更改之前都先要確保對數據庫的所有相關更改均可成功完成。 有關更多信息,請參見事務和併發 (ADO.NET)

使用 TableAdapter 更新兩個相關表

  1. 創建三個臨時數據表以保存不同的記錄。

  2. 從 try/catch 塊中爲每個子行集調用 Update 方法。 如果發生更新錯誤,則應分支出來並解決這些錯誤。

  3. 將更改提交到數據庫。

  4. 處置臨時數據表以釋放資源。

    下面的示例顯示如何用包含相關表的數據集更新數據源。

    C#
    void UpdateDB()
    {
        NorthwindDataSet.OrdersDataTable deletedChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Deleted);
    
        NorthwindDataSet.OrdersDataTable newChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Added);
    
        NorthwindDataSet.OrdersDataTable modifiedChildRecords = 
            (NorthwindDataSet.OrdersDataTable)northwindDataSet.Orders.GetChanges(DataRowState.Modified);
    
        try
        {
            if (deletedChildRecords != null)
            {
                ordersTableAdapter.Update(deletedChildRecords);
            }
    
            customersTableAdapter.Update(northwindDataSet.Customers);
    
            if (newChildRecords != null)
            {
                ordersTableAdapter.Update(newChildRecords);
            }
    
            if (modifiedChildRecords != null)
            {
                ordersTableAdapter.Update(modifiedChildRecords);
            }
    
            northwindDataSet.AcceptChanges();
        }
    
        catch (Exception ex)
        {
            MessageBox.Show("An error occurred during the update process");
            // Add code to handle error here.
        }
    
        finally
        {
            if (deletedChildRecords != null)
            {
                deletedChildRecords.Dispose();
            }
            if (newChildRecords != null)
            {
                newChildRecords.Dispose();
            }
            if (modifiedChildRecords != null)
            {
                modifiedChildRecords.Dispose();
            }
        }
    }
    

如何:將新記錄插入數據庫

若要將新記錄插入數據庫中,您可以使用 TableAdapter.Update 方法,或 TableAdapter 的 DBDirect 方法之一(特別是 TableAdapter.Insert 方法)。 有關更多信息,請參見 TableAdapter 概述

如果您的應用程序不使用 TableAdapters,您就可以使用命令對象與數據庫交互並插入新記錄到其中(例如,SqlCommand)。

當應用程序使用數據集存儲數據時,請使用 TableAdapter.Update 方法。 Update 方法會將所有更改(包括更新、插入以及刪除)發送到數據庫中。

當應用程序使用對象存儲數據時,或者您要對在數據庫中創建新記錄進行更好的控制時,請使用 TableAdapter.Insert 方法。

如果 TableAdapter 沒有 Insert 方法,則意味着或者該 TableAdapter 是爲使用存儲過程而配置的,或者其 GenerateDBDirectMethods 屬性已被設置爲 false。 嘗試從“數據集設計器”內將 TableAdapter 的 GenerateDBDirectMethods 屬性設置爲 true,然後保存該數據集以重新生成 TableAdapter。 如果 TableAdapter 仍沒有 Insert 方法,則該表可能沒有提供足夠的架構信息以區分各行(例如,表中未設置主鍵)。

使用 TableAdapter 插入新記錄

根據應用程序的需要,TableAdapter 提供了將新記錄插入數據庫的不同方法。

如果應用程序使用數據集存儲數據,則可以完全將新記錄添加到數據集中所需的 DataTable,然後調用 TableAdapter.Update 方法。 TableAdapter.Update 方法得到 DataTable 中的所有更改,並將這些更改發送到數據庫中(包括已修改的記錄和刪除的記錄)。

使用 TableAdapter.Update 方法將新記錄插入數據庫

  1. 通過創建新的 DataRow 並將它添加到 Rows 集合中,可將新記錄添加到所需的 DataTable 中。 有關更多信息,請參見如何:向數據表中添加行

  2. 將新行添加到 DataTable 後,請調用 TableAdapter.Update 方法。 通過傳入完整的 DataSetDataTableDataRow 數組或單個 DataRow,您可以控制要更新的數據量。

    下面的代碼顯示如何將新記錄添加到 DataTable 中,然後調用 TableAdapter.Update 方法將新行保存到數據庫中。 (此示例使用 Northwind 數據庫的 Region 表。)

    C#
    // Create a new row.
    NorthwindDataSet.RegionRow newRegionRow;
    newRegionRow = northwindDataSet.Region.NewRegionRow();
    newRegionRow.RegionID = 5;
    newRegionRow.RegionDescription = "NorthWestern";
    
    // Add the row to the Region table
    this.northwindDataSet.Region.Rows.Add(newRegionRow);
    
    // Save the new row to the database
    this.regionTableAdapter.Update(this.northwindDataSet.Region);
    

如果應用程序使用對象存儲應用程序中的數據,您就可以使用 TableAdapter.Insert 方法直接在數據庫中創建新行。 Insert 方法接受將每一列的單個值作爲參數。 調用此方法用傳入的參數值將新記錄插入到數據庫。

以下過程使用 Northwind 數據庫的 Region 表作爲示例。

使用 TableAdapter.Insert 方法將新記錄插入到數據庫

  • 調用 TableAdapter 的 Insert 方法,爲每一列傳入值作爲參數。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Insert(5, "NorthWestern");
    

使用命令對象插入新記錄

下面的示例使用命令對象直接將新記錄插入到數據庫。 有關使用命令對象執行命令和存儲過程的更多信息,請參見 將數據獲取到應用程序

以下過程使用 Northwind 數據庫的 Region 表作爲示例。

使用命令對象將新記錄插入到數據庫

  • 創建新的命令對象,並設置它的 Connection、CommandType 和 CommandText 屬性。

    C#
    System.Data.SqlClient.SqlConnection sqlConnection1 = 
        new System.Data.SqlClient.SqlConnection("YOUR CONNECTION STRING");
    
    System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.CommandText = "INSERT Region (RegionID, RegionDescription) VALUES (5, 'NorthWestern')";
    cmd.Connection = sqlConnection1;
    
    sqlConnection1.Open();
    cmd.ExecuteNonQuery();
    sqlConnection1.Close();
    

安全性

您必須有訪問正嘗試連接到的數據庫的權限,以及在所需表中執行插入的權限。


 

如何:更新數據庫中的記錄

更新:2010 年 9 月

可以使用 TableAdapter.Update 方法更新(編輯)數據庫中的記錄。 TableAdapter.Update 方法根據傳入的參數提供了若干次執行不同操作的重載。 瞭解調用這些不同方法簽名的結果非常重要。

 提示

如果您的應用程序不使用 TableAdapter,您就可以使用命令對象更新數據庫中的記錄(例如,ExecuteNonQuery)。 有關使用命令對象更新數據的更多信息,請參見下面的“使用命令對象更新記錄”。

下表描述了各種 TableAdapter.Update 方法的行爲:

表 1

方法

說明

TableAdapter.Update(DataTable)

嘗試將 DataTable 中的所有更改保存到數據庫中。 (這包括從表中移除所有刪除的行、將插入的行添加到表中、更新表中已更改的所有行。)

TableAdapter.Update(DataSet)

雖然該參數帶有一個數據集,但 TableAdapter 仍嘗試將 TableAdapter 的關聯 DataTable 中的所有更改保存到數據庫中。 (這包括從表中移除所有刪除的行、將插入的行添加到表中、更新表中已更改的所有行。)

注意注意
TableAdapter 的關聯 DataTable 是最初配置 TableAdapter 時創建的 DataTable

TableAdapter.Update(DataRow)

嘗試將指示 DataRow 中的更改保存到數據庫中。

TableAdapter.Update(DataRows())

嘗試將 DataRow 數組中任意行中的更改保存到數據庫中。

TableAdapter.Update("new column values", "original column values")

嘗試保存由原始列值標識的單行中的更改。

通常,當應用程序使用數據集以獨佔方式存儲數據時,您使用的是帶有 DataSetDataTable 或 DataRow 的 TableAdapter.Update 方法。

通常,當應用程序使用對象存儲數據時,您使用的是帶有列值的 TableAdapter.Update 方法。

如果 TableAdapter 沒有帶列值的 Update 方法,就表示已將 TableAdapter 配置爲使用存儲過程,或者已將它的 GenerateDBDirectMethods 屬性設置爲 false。 嘗試從“數據集設計器”內將 TableAdapter 的 GenerateDBDirectMethods 屬性設置爲 true,然後保存該數據集以重新生成 TableAdapter。 如果 TableAdapter 仍沒有帶列值的 Update 方法,該表就可能沒有提供足夠多的架構信息以區分各行(例如,未在表中設置任何主鍵)。

使用 TableAdapter 更新現有記錄

根據應用程序的需要,TableAdapter 提供了更新數據庫中記錄的不同方法。

如果應用程序使用數據集存儲數據,則可以在所需的 DataTable 中簡單地更新記錄,然後調用 TableAdapter.Update 方法並傳入 DataSetDataTableDataRow 或 DataRow 數組。 上表描述了不同的 Update 方法。

用帶有 DataSet、DataTable、DataRow 或 DataRows() 的 TableAdapter.Update 方法更新數據庫中的記錄

  1. 通過直接編輯 DataTable 中的 DataRow,編輯所需的 DataTable 中的記錄。 有關更多信息,請參見 如何:編輯數據表中的行

  2. 在 DataTable 中對行進行編輯後,請調用 TableAdapter.Update 方法。 通過傳入完整的 DataSetDataTableDataRow 數組或單個 DataRow,您可以控制要更新的數據量。

    下面的代碼顯示如何編輯 DataTable 中的記錄,然後調用 TableAdapter.Update 方法將更改保存到數據庫中。 (此示例使用 Northwind 數據庫 Region 表。)

    C#
    // Locate the row you want to update.
    NorthwindDataSet.RegionRow regionRow;
    regionRow = northwindDataSet.Region.FindByRegionID(1);
    
    // Assign the new value to the desired column.
    regionRow.RegionDescription = "East";
    
    // Save the updated row to the database.
    this.regionTableAdapter.Update(this.northwindDataSet.Region);
    

如果應用程序使用對象存儲應用程序中的數據,您就可以使用 TableAdapter 的 DBDirect 方法將數據從對象中直接發送到數據庫。 這些方法可讓您將各列的單個值傳遞爲方法參數。 調用此方法用傳入該方法的列值更新數據庫中的現有記錄。

以下過程使用 Northwind Region 表作爲示例。

使用帶有列值的 TableAdapter.Update 方法更新數據庫中的記錄

  • 調用 TableAdapter 的 Update 方法,以參數的形式爲每一列傳入新值和原始值。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Update(1, "East", 1, "Eastern");
    

使用命令對象更新記錄

下面的示例使用命令對象直接更新數據庫中的現有記錄。 有關使用命令對象執行命令和存儲過程的更多信息,請參見 將數據獲取到應用程序

以下過程使用 Northwind Region 表作爲示例。

使用命令對象更新數據庫中的現有記錄

  • 創建新的命令對象;設置它的 Connection、CommandType 和 CommandText 屬性;然後打開一個連接,並執行該命令。

    C#
    System.Data.SqlClient.SqlConnection sqlConnection1 = 
        new System.Data.SqlClient.SqlConnection("YOUR CONNECTION STRING");
    
    System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.CommandText = "UPDATE Region SET [RegionDescription] = @RegionDescription WHERE [RegionID] = @RegionID";
    cmd.Parameters.AddWithValue("@RegionDescription", "East");
    cmd.Parameters.AddWithValue("@RegionID", "1");
    cmd.Connection = sqlConnection1;
    
    sqlConnection1.Open();
    cmd.ExecuteNonQuery();
    sqlConnection1.Close();
    

安全性

您必須具有訪問正嘗試連接到的數據庫的權限,以及更新所需表中記錄的權限。


 

如何:刪除數據庫中的記錄

要從數據庫中刪除記錄,請使用 TableAdapter.Update 方法或 TableAdapter.Delete 方法。 或者,如果您的應用程序不使用 TableAdapters,您就可以使用命令對象從數據庫中刪除記錄(例如,ExecuteNonQuery)。

當應用程序使用數據集存儲數據時通常使用 TableAdapter.Update 方法,而當應用程序使用對象存儲數據時通常會使用 TableAdapter.Delete 方法。

如果 TableAdapter 沒有 Delete 方法,則意味着或者該 TableAdapter 是爲使用存儲過程而配置的,或者其 GenerateDBDirectMethods 屬性被設置爲 false。 嘗試從“數據集設計器”內將 TableAdapter 的 GenerateDBDirectMethods 屬性設置爲 true,然後保存該數據集以重新生成 TableAdapter。 如果 TableAdapter 仍沒有 Delete 方法,那麼該表可能沒有提供足夠的架構信息在單個行之間進行區分(例如,表中未設置主鍵)。

使用 TableAdapters 刪除記錄

根據應用程序的需要,TableAdapters 提供了從數據庫中刪除記錄的不同方法。

如果應用程序使用數據集存儲數據,則可以直接從 DataSet 中所需的 DataTable 中刪除記錄,然後調用 TableAdapter.Update 方法。 TableAdapter.Update 方法得到數據表中的所有更改,並將這些更改發送到數據庫中(包括插入、更新以及刪除記錄)。

使用 TableAdapter.Update 方法從數據庫中刪除記錄

  • 通過從表中刪除 DataRow 對象,從所需 DataTable 中刪除記錄。 有關更多信息,請參見如何:刪除數據表中的行。 從 DataTable 中刪除行後,請調用 TableAdapter.Update 方法。 通過傳入完整的 DataSetDataTableDataRow 數組或單個 DataRow,您可以控制要更新的數據量。 下面的代碼顯示如何從 DataTable 中刪除記錄,然後調用 TableAdapter.Update 方法傳達更改並從數據庫中刪除行 (此示例使用 Northwind 數據庫的 Region 表)。

    C#
    // Locate the row to delete.
    NorthwindDataSet.RegionRow oldRegionRow;
    oldRegionRow = northwindDataSet.Region.FindByRegionID(5);
    
    // Delete the row from the dataset
    oldRegionRow.Delete();
    
    // Delete the row from the database
    this.regionTableAdapter.Update(this.northwindDataSet.Region);
    

如果應用程序使用對象存儲應用程序中的數據,您就可以使用 TableAdapter 的 DBDirect 方法直接從數據庫中刪除數據。 根據傳入的參數值,調用 Delete 方法從數據庫中移除記錄。

使用 TableAdapter.Delete 方法從數據庫中刪除記錄

  • 調用 TableAdapter 的 Delete 方法,爲每一列傳入值作爲 Delete 方法的參數 (此示例使用 Northwind 數據庫的 Region 表)。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Delete(5, "NorthWestern");
    

使用命令對象刪除記錄

下面的示例使用命令對象直接從數據庫中刪除記錄。 有關使用命令對象執行命令和存儲過程的更多信息,請參見將數據獲取到應用程序

使用命令對象從數據庫中刪除記錄

  • 創建新的命令對象,並設置它的 Connection、CommandType 和 CommandText 屬性 (此示例使用 Northwind 數據庫的 Region 表)。

    C#
    System.Data.SqlClient.SqlConnection sqlConnection1 = 
        new System.Data.SqlClient.SqlConnection("YOUR CONNECTION STRING ");
    
    System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.CommandText = "DELETE Region WHERE RegionID = 5 AND RegionDescription = 'NorthWestern'";
    cmd.Connection = sqlConnection1;
    
    sqlConnection1.Open();
    cmd.ExecuteNonQuery();
    sqlConnection1.Close();
    

安全性

您必須具有訪問正在嘗試連接到的數據庫的權限,以及從所需表中刪除記錄的權限。

如何:使用 TableAdapter 直接訪問數據庫

除了 InsertCommand、UpdateCommand 和 DeleteCommand 之外,創建 TableAdapter 時還生成了一些可以直接在數據庫上執行的方法。 可以直接調用這些方法(TableAdapter.Insert、TableAdapter.Update 和 TableAdapter.Delete)對數據庫中的數據進行操作。

如果不想創建這些直接方法,可在**“屬性”**窗口中將 TableAdapter 的 GenerateDbDirectMethods 屬性設置爲 false。 除了 TableAdapter 的主查詢之外,所有添加到 TableAdapter 的查詢也是獨立查詢 -- 它們不生成這些 DbDirect 方法。

直接向數據庫發送命令

調用執行您嘗試完成的任務的 TableAdapter DbDirect 方法。

直接向數據庫中插入新記錄

  • 調用 TableAdapter 的 Insert 方法,爲每一列傳入值作爲參數。 以下過程使用 Northwind 數據庫的 Region 表作爲示例。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Insert(5, "NorthWestern");
    

直接在數據庫中更新記錄

  • 調用 TableAdapter 的 Update 方法,以參數的形式爲每一列傳入新值和原始值。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Update(1, "East", 1, "Eastern");
    

直接從數據庫中刪除記錄

  • 調用 TableAdapter 的 Delete 方法,爲每一列傳入值作爲 Delete 方法的參數 (此示例使用 Northwind 數據庫的 Region 表)。

     提示

    如果沒有實例可用,請實例化您要使用的 TableAdapter。

    C#
    NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter = 
        new NorthwindDataSetTableAdapters.RegionTableAdapter();
    
    regionTableAdapter.Delete(5, "NorthWestern");
    

如何:將數據從對象保存到數據庫

通過將對象中的值傳遞到 TableAdapter 的 DBDirect 方法之一(例如,TableAdapter.Insert),可將對象中的數據保存到數據庫中。 有關更多信息,請參見 TableAdapter 概述

若要保存對象集合中的數據,請循環通過對象集合(例如,for-next 循環),然後使用 TableAdapter 的 DBDirect 方法之一將每個對象的值發送到數據庫中。

默認情況下,DBDirect 方法在 TableAdapter 上創建,能夠直接對數據庫執行操作。 這些方法可以直接調用,它們不要求 DataSet 或 DataTable 對象來協調更改即可將更新發送到數據庫。

 提示

配置 TableAdapter 時,主查詢必須提供足夠的信息,才能創建 DBDirect 方法。 例如,如果將 TableAdapter 配置爲從未定義主鍵列的表中查詢數據,它將不會生成 DBDirect 方法。

表 1

TableAdapter DBDirect 方法

說明

TableAdapter.Insert

向數據庫中添加新記錄,此方法允許將值作爲方法參數傳入各個列。

TableAdapter.Update

更新數據庫中的現有記錄。 Update 方法將原始列值和新列值用作方法參數。 原始值用於定位原始記錄,新值用於更新該記錄。

通過將 DataSetDataTableDataRow、或 DataRow 數組用作方法參數,TableAdapter.Update 方法還可用於將數據集中的更改協調回數據庫。

TableAdapter.Delete

在基於作爲方法參數傳入的原始列值的數據庫中,刪除其現有記錄。

將對象中的新記錄保存到數據庫中

  • 通過將值傳遞給 TableAdapter.Insert 方法可創建這些記錄。

    下面的示例通過將 currentCustomer 對象中的值傳遞給 TableAdapter.Insert 方法,在 Customers 表中創建一項新的客戶記錄。

    C#
    private void AddNewCustomers(Customer currentCustomer)
    {
        customersTableAdapter.Insert( 
            currentCustomer.CustomerID, 
            currentCustomer.CompanyName, 
            currentCustomer.ContactName, 
            currentCustomer.ContactTitle, 
            currentCustomer.Address, 
            currentCustomer.City, 
            currentCustomer.Region, 
            currentCustomer.PostalCode, 
            currentCustomer.Country, 
            currentCustomer.Phone, 
            currentCustomer.Fax);
    }
    

將對象中的現有記錄更新到數據庫

  • 修改記錄:調用 TableAdapter.Update 方法並傳入新值可更新記錄,而傳入原始值可定位記錄。

     提示

    對象需要保留其原始值,才能將它們傳遞給 Update 方法。 此示例使用前綴爲 orig 的屬性存儲原始值。

    下面的示例通過將 Customer 對象中的新值和原始值傳遞給 TableAdapter.Update 方法,更新 Customers 表中的現有記錄。

    C#
    private void UpdateCustomer(Customer cust)
    {
        customersTableAdapter.Update(
            cust.CustomerID,
            cust.CompanyName,
            cust.ContactName,
            cust.ContactTitle,
            cust.Address,
            cust.City,
            cust.Region,
            cust.PostalCode,
            cust.Country,
            cust.Phone,
            cust.Fax,
            cust.origCustomerID,
            cust.origCompanyName,
            cust.origContactName,
            cust.origContactTitle,
            cust.origAddress,
            cust.origCity,
            cust.origRegion,
            cust.origPostalCode,
            cust.origCountry,
            cust.origPhone,
            cust.origFax);
    }
    

刪除數據庫中的現有記錄

  • 通過調用 TableAdapter.Delete 方法並傳入原始值定位記錄,可刪除記錄。

     提示

    對象需要保留其原始值,才能將它們傳遞給 Delete 方法。 此示例使用前綴爲 orig 的屬性存儲原始值。

    下面的示例通過將 Customer 對象中的原始值傳遞給 TableAdapter.Delete 方法,刪除 Customers 表中的記錄。

    C#
    private void DeleteCustomer(Customer cust)
    {
        customersTableAdapter.Delete(
            cust.origCustomerID,
            cust.origCompanyName,
            cust.origContactName,
            cust.origContactTitle,
            cust.origAddress,
            cust.origCity,
            cust.origRegion,
            cust.origPostalCode,
            cust.origCountry,
            cust.origPhone,
            cust.origFax);
    }
    

安全性

您必須具有相應的權限,才能對數據庫中的表執行選定的 INSERT、UPDATE 或 DELETE。


 

如何:使用事務保存數據

使用 System.Transactions 命名空間在事務中保存數據。 使用 TransactionScope 對象來參與爲您自動管理的事務。

項目不是用對 System.Transactions 程序集的引用創建的,因此您需要向使用事務的項目手動添加引用。

 提示

Windows 2000 和更高版本支持 System.Transactions 命名空間。

實現事務的最簡便方法是在 using 語句中實例化 TransactionScope 對象。 (有關更多信息,請參見 Using 語句 (Visual Basic) 和 using 語句(C# 參考)。)using 語句內執行的代碼將參與事務。

若要提交事務,請調用作爲 using 塊中最後語句的 Complete 方法。

若要回滾事務,請在調用 Complete 方法之前,引發異常。

有關更多信息,請參見 演練:在事務中保存數據

添加對 System.Transactions dll 的引用

  1. 從**“項目”菜單中選擇“添加引用”**。

  2. 在**“.NET”選項卡(SQL Server 項目的“SQL Server”選項卡)上選擇“System.Transactions”,並單擊“確定”**。

    對 System.Transactions.dll 的引用被添加到項目中。

在事務中保存數據

  • 添加代碼以在包含事務的 using 語句內保存數據。 下面的代碼顯示如何在 using 語句中創建和實例化 TransactionScope 對象:

    C#
    using (System.Transactions.TransactionScope updateTransaction = 
        new System.Transactions.TransactionScope())
    {
        // Add code to save your data here.
        // Throw an exception to roll back the transaction.
    
        // Call the Complete method to commit the transaction
        updateTransaction.Complete();
    }
    

演練:將數據保存到數據庫(多個表)

更新:2011 年 5 月

應用程序開發中最常用方案之一是在 Windows 應用程序窗體中顯示數據、編輯數據並將更新後的數據發回數據庫。 本演練創建可顯示兩個相關表的數據的窗體,並演示如何編輯記錄和將更改保存回數據庫。 此示例使用源自 Northwind 示例數據庫的 Customers 和 Orders 表。

通過調用 TableAdapter 的 Update 方法,可以將應用程序中的數據保存回數據庫。 當從**“數據源”**窗口拖動項時,爲拖放到窗體上的第一個表自動添加保存數據的代碼。 添加到窗體的任何其他表都要求手動添加保存數據所需的所有代碼。 本演練演示如何添加從多個表保存更新的代碼。

 提示

顯示的對話框和菜單命令可能會與“幫助”中的描述不同,具體取決於您現用的設置或版本。 若要更改設置,請在“工具”菜單上選擇“導入和導出設置”。 有關更多信息,請參見 使用設置

本演練涉及以下任務:

系統必備

若要完成本演練,您需要:

創建 Windows 應用程序

第一步是創建**“Windows 應用程序”**。 在此步驟中爲項目指定名稱是可選的,但由於我們打算稍後保存該項目,因此爲它指定了一個名稱。

創建新的 Windows 應用程序項目

  1. 從**“文件”**菜單創建一個新的項目。

  2. 將項目命名爲 UpdateMultipleTablesWalkthrough。

  3. 選擇**“Windows 應用程序”,然後單擊“確定”**。 有關更多信息,請參見 創建基於 Windows 的應用程序

    UpdateMultipleTablesWalkthrough 項目即被創建並添加到**“解決方案資源管理器”**中。

創建數據源

此步驟使用**“數據源配置嚮導”**從 Northwind 數據庫創建一個數據源。 您必須具有訪問 Northwind 示例數據庫的權限,才能創建連接。 有關設置 Northwind 示例數據庫的信息,請參見 如何:安裝示例數據庫

創建數據源

  1. 在**“數據”菜單上,單擊“顯示數據源”**。

  2. 在**“數據源”窗口中,單擊“添加新數據源”,啓動“數據源配置嚮導”**。

  3. 在**“選擇數據源類型”頁上選擇“數據庫”,然後單擊“下一步”**。

  4. 在**“選擇您的數據連接”**頁面上執行下列操作之一:

    • 如果下拉列表中包含到 Northwind 示例數據庫的數據連接,請選擇該連接。

      - 或 -

    • 選擇**“新建連接”,打開“添加/修改連接”**對話框。 有關更多信息,請參見 “添加/修改連接”對話框(通用)

  5. 如果數據庫需要密碼,請選擇該選項以包括敏感數據,再單擊**“下一步”**。

  6. 在**“將連接字符串保存到應用程序配置文件”頁面上單擊“下一步”**。

  7. 在**“選擇數據庫對象”頁面上展開“表”**節點。

  8. 選擇**“Customers”和“Orders”表,然後單擊“完成”**。

    **“NorthwindDataSet”被添加到您的項目,這些表將出現在“數據源”**窗口中。

設置要創建的控件

對於本演練,Customers 表中的數據將處於**“詳細信息”佈局(數據在單獨控件中顯示)。 來自 Orders 表的數據將處於“網格”**佈局(在 DataGridView 控件中顯示)。

設置數據源窗口中項的放置類型

  1. 在**“數據源”窗口中展開“Customers”**節點。

  2. 通過從**“Customers”節點上的控件列表中選擇“詳細信息”,將“Customers”**表中的控件更改爲單獨的控件。 有關更多信息,請參見 如何:設置從“數據源”窗口中拖動時要創建的控件

創建數據綁定窗體

可以通過將某些項從**“數據源”**窗口拖到您的窗體上來創建數據綁定控件。

在窗體上創建數據綁定控件

  1. 將主**“Customers”節點從“數據源”窗口拖到“Form1”**上。

    帶有描述性標籤的數據綁定控件會出現在窗體上,同時還顯示一個工具條 (BindingNavigator),用於在記錄間進行導航。 組件欄中出現 NorthwindDataSetCustomersTableAdapterBindingSource 和 BindingNavigator

  2. 將相關的**“Orders”節點從“數據源”窗口拖動到“Form1”**上。

     提示

    相關的“Orders”節點位於“Fax”列下,該節點是“Customers”節點的子節點。

    用於導航記錄的 DataGridView 控件和工具條 (BindingNavigator) 出現在窗體上。 OrdersTableAdapter 和 BindingSource 出現在組件欄中。

添加用於更新數據庫的代碼

通過調用**“Customers”和“Orders”TableAdapter 的 Update 方法可以更新數據庫。 默認情況下,BindingNavigator 的“保存”**按鈕的事件處理程序被添加到窗體代碼中,以將更新內容發送到數據庫。 本過程將修改該代碼以按正確的順序發送更新內容,從而消除產生引用完整性錯誤的可能性。 該代碼還將通過在 try-catch 塊中包裝更新調用來實現錯誤處理。 可以根據應用程序的需要修改代碼。

 提示

爲了清楚起見,本演練未使用事務,但是如果您要更新兩個或多個相關表,則應在一個事務中包含所有更新邏輯。 事務是指一個過程,它首先確保對數據庫的所有相關更改均可成功完成,然後再提交更改。 有關更多信息,請參見 事務和併發 (ADO.NET)

嚮應用程序添加更新邏輯

  1. 在 BindingNavigator 上雙擊**“保存”**按鈕,打開代碼編輯器並轉到 bindingNavigatorSaveItem_Click 事件處理程序。

  2. 替換事件處理程序中的代碼以調用相關 TableAdapter 的 Update 方法。 下面的代碼首先創建三個臨時數據表以保存每個 DataRowState 的更新信息(DeletedAdded 和 Modified)。 然後,按正確的順序執行更新。 代碼應類似於:

    C#
    this.Validate();
    this.ordersBindingSource.EndEdit();
    this.customersBindingSource.EndEdit();
    
    NorthwindDataSet.OrdersDataTable deletedOrders = (NorthwindDataSet.OrdersDataTable)
        northwindDataSet.Orders.GetChanges(DataRowState.Deleted);
    
    NorthwindDataSet.OrdersDataTable newOrders = (NorthwindDataSet.OrdersDataTable)
        northwindDataSet.Orders.GetChanges(DataRowState.Added);
    
    NorthwindDataSet.OrdersDataTable modifiedOrders = (NorthwindDataSet.OrdersDataTable)
        northwindDataSet.Orders.GetChanges(DataRowState.Modified);
    
    try
    {
        // Remove all deleted orders from the Orders table.
        if (deletedOrders != null)
        {
            ordersTableAdapter.Update(deletedOrders);
        }
    
        // Update the Customers table.
        customersTableAdapter.Update(northwindDataSet.Customers);
    
        // Add new orders to the Orders table.
        if (newOrders != null)
        {
            ordersTableAdapter.Update(newOrders);
        }
    
        // Update all modified Orders.
        if (modifiedOrders != null)
        {
            ordersTableAdapter.Update(modifiedOrders);
        }
    
        northwindDataSet.AcceptChanges();
    }
    
    catch (System.Exception ex)
    {
        MessageBox.Show("Update failed");
    }
    
    finally
    {
        if (deletedOrders != null)
        {
            deletedOrders.Dispose();
        }
        if (newOrders != null)
        {
            newOrders.Dispose();
        }
        if (modifiedOrders != null)
        {
            modifiedOrders.Dispose();
        }
    }
    

測試應用程序

測試應用程序

  1. 按 F5。

  2. 對每個表中的一條或多條記錄的數據執行一些更改。

  3. 按**“保存”**按鈕。

  4. 檢查數據庫中的值以驗證更改已保存。

     提示

    有關演示如何在更改 Customers 或添加新 Customer 和 Orders 數據後更新 Orders 列表的示例代碼,請參見如何:將新記錄插入數據庫演練:保存相關數據表中的數據(分層更新)

後續步驟

根據應用程序的要求,在 Windows 應用程序中創建了綁定數據窗體後,還需要執行一些步驟。 您可以通過以下操作來增強此演練的效果:


 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章