1. 程式人生 > >使用 DataAdapter 和 DataSet 更新資料庫

使用 DataAdapter 和 DataSet 更新資料庫

DataAdapter   的 Update 方法可呼叫來將 DataSet 中的更改解析回資料來源。與 Fill 方法類似,Update 方法將 DataSet 的例項和可選的 DataTable 物件或 DataTable 名稱用作引數。DataSet 例項是包含已作出的更改的 DataSet,而 DataTable 標識從其中檢索更改的表。

當呼叫 Update 方法時,DataAdapter 將分析已作出的更改並執行相應的命令(INSERT、UPDATE 或 DELETE)。當 DataAdapter 遇到對 DataRow 的更改時,它將使用 InsertCommandUpdateCommand

DeleteCommand 來處理該更改。這樣,您就可以通過在設計時指定命令語法並在可能時通過使用儲存過程來儘量提高 ADO.NET 應用程式的效能。在呼叫 Update 之前,必須顯式設定這些命令。如果呼叫了 Update 但不存在用於特定更新的相應命令(例如,不存在用於已刪除行的 DeleteCommand),則將引發異常。

Command 引數可用於為 DataSet 中每個已修改行的 SQL 語句或儲存過程指定輸入和輸出值。有關更多資訊,請參閱將引數用於 DataAdapter

如果 DataTable 對映到單個數據庫表或從單個數據庫表生成,則可以利用 CommandBuilder

物件自動生成 DataAdapter DeleteCommandInsertCommandUpdateCommand。有關更多資訊,請參閱自動生成的命令

Update 方法會將更改解析回資料來源,但是自上次填充 DataSet 以來,其他客戶端可能已修改了資料來源中的資料。若要使用當前資料重新整理 DataSet,請再次使用 DataAdapter 填充 (Fill) DataSet。新行將新增到該表中,更新的資訊將併入現有行。

若要處理可能在 Update 操作過程中發生的異常,可以使用 RowUpdated 事件在這些異常發生時響應行更新錯誤(請參閱使用 DataAdapter 事件

),或者可以在呼叫 Update 之前將 DataAdapter.ContinueUpdateOnError 設定為 true,然後在 Update 完成時響應儲存在特定行的 RowError 屬性中的錯誤資訊(請參閱新增和讀取行錯誤資訊)。

注意 如果對 DataSetDataTableDataRow 呼叫 AcceptChanges,則將使某 DataRow 的所有 Original 值被該 DataRowCurrent 值改寫。如果已修改將該行標識為唯一行的欄位值,那麼當呼叫 AcceptChanges 後,Original 值將不再匹配資料來源中的值。

以下示例演示如何通過顯式設定 DataAdapterUpdateCommand 來執行對已修改行的更新。請注意,在 UPDATE 語句的 WHERE 子句中指定的引數設定為使用 SourceColumnOriginal 值。這一點很重要,因為 Current 值可能已被修改,並且可能不匹配資料來源中的值。Original 值是曾用來從資料來源填充 DataTable 的值。

SqlClient

Dim catDA As SqlDataAdapter = New SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn)

catDA.UpdateCommand = New SqlCommand("UPDATE Categories SET CategoryName = @CategoryName WHERE CategoryID = @CategoryID", nwindConn)

catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

Dim workParm As SqlParameter = catDA.UpdateCommand.Parameters.Add("@CategoryID", SqlDbType.Int)
workParm.SourceColumn = "CategoryID"
workParm.SourceVersion = DataRowVersion.Original

Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")  

Dim cRow As DataRow = catDS.Tables("Categories").Rows(0)
cRow("CategoryName") = "New Category"

catDA.Update(catDS)

SqlDataAdapter catDA = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);       

catDA.UpdateCommand = new SqlCommand("UPDATE Categories SET CategoryName = @CategoryName WHERE CategoryID = @CategoryID" , nwindConn);

catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

SqlParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", SqlDbType.Int);
workParm.SourceColumn = "CategoryID";
workParm.SourceVersion = DataRowVersion.Original;

DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");   

DataRow cRow = catDS.Tables["Categories"].Rows[0];
cRow["CategoryName"] = "New Category";

catDA.Update(catDS);

OleDb

Dim catDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn)       

catDA.UpdateCommand = New OleDbCommand("UPDATE Categories SET CategoryName = ? WHERE CategoryID = ?" , nwindConn)

catDA.UpdateCommand.Parameters.Add("@CategoryName", OleDbType.VarChar, 15, "CategoryName")

Dim workParm As OleDbParameter = catDA.UpdateCommand.Parameters.Add("@CategoryID", OleDbType.Integer)
workParm.SourceColumn = "CategoryID"
workParm.SourceVersion = DataRowVersion.Original

Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")    

Dim cRow As DataRow = catDS.Tables("Categories").Rows(0)
cRow("CategoryName") = "New Category"

catDA.Update(catDS)

OleDbDataAdapter catDA = new OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);            

catDA.UpdateCommand = new OleDbCommand("UPDATE Categories SET CategoryName = ? WHERE CategoryID = ?" , nwindConn);

catDA.UpdateCommand.Parameters.Add("@CategoryName", OleDbType.VarChar, 15, "CategoryName");

OleDbParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", OleDbType.Integer);
workParm.SourceColumn = "CategoryID";
workParm.SourceVersion = DataRowVersion.Original;

DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");    

DataRow cRow = catDS.Tables["Categories"].Rows[0];
cRow["CategoryName"] = "New Category";
catDA.Update(catDS);

自動遞增列

如果來自資料來源的表包含自動遞增列,則可以使用由資料來源生成的值填充 DataSet 中的列,方法是通過以儲存過程輸出引數的形式返回自動遞增值並將其對映到表中的一列,或者使用 DataAdapterRowUpdated 事件。有關示例,請參閱檢索“標識”或“自動編號”值。

但是,DataSet 中的值可能會與資料來源中的值不同步並導致意外的行為。例如,請考慮一個包含自動遞增主鍵列 CustomerID 的表。如果在該 DataSet 中新增兩個新客戶,它們將收到自動遞增的 CustomerId12。在向 DataAdapter Update 方法傳遞第二個客戶行時,新新增的行會收到資料來源中的自動遞增 CustomerID1,該值與 DataSet 中的值 2 不匹配。當 DataAdapter 使用返回值填充 DataSet 中的行時,由於第一個客戶行的 CustomerID 已經是 1,因此將發生約束衝突。

為了避免這種行為,建議在使用資料來源中的自動遞增列和 DataSet 中的自動遞增列時,在 DataSet 中建立 AutoIncrementStep 為 -1 且 AutoIncrementSeed 為 0 的列,並確保資料來源生成從 1 開始並以正步長值遞增的自動遞增標識值。這樣,DataSet 將為自動遞增值生成負數,這些負數不會與資料來源所生成的正自動遞增值發生衝突。另一種方法是使用 Guid 型別的列而不是自動遞增列。生成 Guid 值的演算法在 DataSet 中生成的 Guid 從不會與資料來源生成的 Guid 相同。有關定義 DataTable 中的列的更多資訊,請參閱定義資料表的架構。

插入、更新和刪除的排序

在許多情況下,以何種順序向資料來源傳送通過 DataSet 作出的更改是相當重要的。例如,如果已更新現有行的主鍵值並且添加了具有新主鍵值的新行,則務必要在處理插入之前處理更新。

可以使用 DataTableSelect 方法來返回僅引用具有特定 RowStateDataRow 陣列。然後可以將返回的 DataRow 陣列傳遞到 DataAdapterUpdate 方法來處理已修改的行。通過指定要更新的行的子集,可以控制處理插入、更新和刪除的順序。

例如,以下程式碼確保首先處理表中已刪除的行,然後處理已更新的行,然後處理已插入的行。

Dim updTable As DataTable = custDS.Tables("Customers")

' First process deletes.
custDA.Update(updTable.Select(Nothing, Nothing, DataViewRowState.Deleted))

' Next process updates.
custDA.Update(updTable.Select(Nothing, Nothing, DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
custDA.Update(updTable.Select(Nothing, Nothing, DataViewRowState.Added))

DataTable updTable = custDS.Tables["Customers"];

// First process deletes.
custDA.Update(updTable.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
custDA.Update(updTable.Select(null, null, DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
custDA.Update(updTable.Select(null, null, DataViewRowState.Added));

Update 方法可呼叫來將 DataSet 中的更改解析回資料來源。與 Fill 方法類似,Update 方法將 DataSet 的例項和可選的 DataTable 物件或 DataTable 名稱用作引數。DataSet 例項是包含已作出的更改的 DataSet,而 DataTable 標識從其中檢索更改的表