共用方式為


使用 DataAdapter 和 DataSet 更新資料庫

DataAdapterUpdate 方法會被呼叫來將變更從 DataSet 解析回資料來源。Update 方法類似 Fill 方法,會將 DataSet 的執行個體、選擇性的 DataTable 物件或 DataTable 名稱當作引數。DataSet 執行個體是包含變更內容的 DataSet,而 DataTable 則識別該從那個資料表擷取變更。

當您呼叫 Update 方法時,DataAdapter 會分析已進行的變更,並執行適當的命令 (INSERT、UPDATE 或 DELETE)。DataAdapter 發現 DataRow 有變更時,會使用 InsertCommandUpdateCommandDeleteCommand 來處理變更。如此可讓您於設計階段指定命令語法;在可能的情況下,請儘量在預存程序使用過程中如此處理,使 ADO.NET 應用程式的效能達到最高。您必須在呼叫 Update 前明確地設定命令。如果呼叫 Update 後,特定更新沒有適當命令可用 (例如,刪除的資料列沒有 DeleteCommand),便會擲回例外狀況。

Command 參數可用來指定 SQL 陳述式的輸入和輸出值,或為 DataSet 內每個經過修改的資料列指定預存程序。如需詳細資訊,請參閱使用參數配合 DataAdapter

如果您的 DataTable 對應至或產生自單一資料庫資料表,則您可以利用 CommandBuilder 物件自動產生 DataAdapterDeleteCommandInsertCommandUpdateCommand。如需詳細資訊,請參閱自動產生的命令

Update 方法會將您的變更解析回資料來源,但是自從您上次填入 DataSet 後,其他的用戶端可能也已經修改資料來源的資料。若要以目前的資料重新整理您的 DataSet,請使用 DataAdapter 並以 Fill 再次填入 DataSet。如此新資料列會加入資料表,而更新資訊也會合併入現有資料列。Fill 方法藉由檢查 DataSet 中資料列的主索引鍵值以及 SelectCommand 所傳回的資料列,來決定是否加入新資料列或更新現有資料列。如果 Fill 方法碰到 DataSet 中資料列的主索引鍵值符合 SelectCommand 傳回結果中資料列的主索引鍵值,它就會以 SelectCommand 傳回的資料列中的資訊更新現有資料列,並將該資料列的 RowState 設定為 Unchanged。如果 SelectCommand 傳回之資料列的主索引鍵值與 DataSet 中資料列的任何主索引鍵值都不相符,Fill 方法就加入 RowState 設定為 Unchanged 的新資料列。

**注意   **如果 SelectCommand 傳回 OUTER JOIN 的結果,DataAdapter 將不會為產生的 DataTable 設定 PrimaryKey 值。您將需要自己定義 PrimaryKey,以確保重複資料列正確解析。如需詳細資訊,請參閱定義資料表的主索引鍵

若要處理 Update 過程中可能發生的例外狀況,您可使用 RowUpdated 事件在出現資料列更新錯誤時進行回應 (請參閱使用 DataAdpater 事件),也可以在呼叫 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)
[C#]
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)
[C#]
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);

Odbc

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

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

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

Dim workParm As OdbcParameter = catDA.UpdateCommand.Parameters.Add("@CategoryID", OdbcType.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"

Dim modRows() As DataRow = catDS.Tables("Categories").Select(Nothing, Nothing, DataViewRowState.ModifiedCurrent)

catDA.Update(modRows)
[C#]
OdbcDataAdapter catDA = new OdbcDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);

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

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

OdbcParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", OdbcType.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";

DataRow[] modRows = catDS.Tables["Categories"].Select(null, null, DataViewRowState.ModifiedCurrent);
catDA.Update(modRows);

AutoIncrement 資料行

如果來自您資料來源的資料表具有自動遞增的資料行,則您可以使用資料來源產生的值填入 DataSet 內的資料行,方法是將自動遞增值當成預存程序的參數傳回,並將此值對應至資料表資料行;使用 DataAdapterRowUpdated 事件也可以達成同樣目的。如需相關範例,請參閱擷取識別或 Autonumber 值

但是,DataSet 內的值可能會與資料來源的值不同步,而造成未預期的行為。舉例來說,假設有個資料表具有自動遞增主索引鍵資料行 CustomerID。如果您在 DataSet 內加入兩個客戶,則它們會收到自動遞增的 CustomerId12。而將第二個客戶資料列傳遞給 DataAdapterUpdate 方法後,資料來源中新加入的資料列便會收到自動遞增的 CustomerID1,這與 DataSet 內的值 2 不相符。DataAdapter 使用這個傳回值填入 DataSet 中的資料列時,會發生條件約束違規,因為第一個客戶資料列已經具有值為 1CustomerID

若要避免發生這種行為,建議您在資料來源和 DataSet 內使用自動遞增資料行時,在 DataSet 內建立 AutoIncrementStep 值為 -1 以及 AutoIncrementSeed 值為 0 的資料行,同時請確定您的資料來源產生的自動遞增識別 (Identity) 值從 1 開始,並以正 Step 值遞增。這樣一來,DataSet 便能替自動遞增值產生負值,而不會和資料來源所產生的正自動遞增值有衝突。另一項選擇是使用 Guid 型別的資料行來取代自動遞增資料行。產生 Guid 的演算法永遠不會在 DataSet 內產生與資料來源所產生的相同的 Guid。如需定義 DataTable 內資料行的詳細資訊,請參閱定義 DataTable 的結構描述

插入、更新和刪除的順序

許多情況下,以何種順序將透過 DataSet 所進行的變更傳送給資料來源是很重要的。例如,如果更新了現有資料列的主索引鍵值,也加入了具有新主索引鍵值的資料列,則先進行更新再執行插入是很重要的。

您可以使用 DataTableSelect 方法,傳回只以特定 RowState 參考資料列的 DataRow 陣列。接著,您可以將傳回的 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))
[C#]
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));

請參閱

使用 .NET Framework 資料提供者存取資料 | DataSet 類別 | DataTable 類別 | OleDbDataAdapter 類別 | OdbcDataAdapter 類別 | SqlDataAdapter 類別