調用 DataAdapter 的 Update 方法可以将 DataSet 中的更改解析回資料源。 與 Fill 方法類似,Update 方法将 DataSet 的執行個體和可選的 DataTable 對象或 DataTable 名稱用作參數。 DataSet 執行個體是包含已做的更改的 DataSet,DataTable 辨別從其中檢索這些更改的表。 如果未指定 DataTable,則使用 DataSet 中的第一個 DataTable。
當調用 Update 方法時,DataAdapter 會分析已做的更改并執行相應的指令(INSERT、UPDATE 或 DELETE)。 當 DataAdapter 遇到對 DataRow 所做的更改時,它将使用 InsertCommand、UpdateCommand 或 DeleteCommand 來處理該更改。 這樣,您就可以通過在設計時指定指令文法并在可能時通過使用存儲過程來盡量提高 ADO.NET 應用程式的性能。 在調用 Update 之前,必須顯式設定這些指令。 如果調用了 Update 但不存在用于特定更新的相應指令(例如,不存在用于已删除行的 DeleteCommand),則會引發異常。
![]() |
---|
如果您要通過 SQL Server 存儲過程使用 DataAdapter 來編輯或删除資料,請確定不要在存儲過程定義中使用 SET NOCOUNT ON。 這将使傳回的受影響的行數為零,DataAdapter 會将其解釋為并發沖突。 在這種情況下,将引發 DBConcurrencyException。 |
可以使用指令參數為 DataSet 中每個已修改的行指定 SQL 語句或存儲過程的輸入和輸出值。 有關更多資訊,請參見DataAdapter 參數 (ADO.NET)。
![]() |
---|
必須了解在 DataTable 中删除行和移除行之間的差異。 當調用 Remove 或 RemoveAt 方法時,會立即移除該行。 如果之後将 DataTable 或 DataSet 傳遞給 DataAdapter 并調用 Update,則不會影響後端資料源中的任何相應行。 當您使用 Delete 方法時,該行仍将保留在 DataTable 中并會标記為删除。 如果之後将 DataTable 或 DataSet 傳遞給 DataAdapter 并調用 Update,則會删除後端資料源中的相應行。 |
如果 DataTable 映射到單個資料庫表或從單個資料庫表生成,則可以利用 DbCommandBuilder 對象為 DataAdapter 自動生成 DeleteCommand、InsertCommand 和 UpdateCommand 對象。 有關更多資訊,請參見使用 CommandBuilder 生成指令 (ADO.NET)。
使用 UpdatedRowSource 将值映射到資料集
通過使用 DbCommand 對象的 UpdatedRowSource 屬性,您可以在調用 DataAdapter 的 Update 方法後控制從資料源傳回的值映射回 DataTable 的方式。 通過将 UpdatedRowSource 屬性設定為 UpdateRowSource 枚舉值之一,您可以控制是忽略由 DataAdapter 指令傳回的輸出參數還是将其應用于 DataSet 中已更改的行。 還可以指定是否将傳回的第一行(如果存在)應用于 DataTable 中已更改的行。
下表說明 UpdateRowSource 枚舉的不同值,并說明它們如何影響與 DataAdapter 一起使用的指令的行為。
UpdatedRowSource 枚舉 | 說明 |
---|---|
Both | 輸出參數和傳回的結果集的第一行都可以映射到 DataSet 中已更改的行。 |
FirstReturnedRecord | 隻有傳回的結果集的第一行中的資料才可以映射到 DataSet 中已更改的行。 |
None | 忽略任何輸出參數或傳回的結果集中的行。 |
OutputParameters | 隻有輸出參數才可以映射到 DataSet 中已更改的行。 |
Update 方法會将更改解析回資料源;但在上次填充 DataSet 後,其他用戶端可能已修改了資料源中的資料。 若要使用目前資料重新整理 DataSet,請使用 DataAdapter 和 Fill 方法。 新行将添加到該表中,更新的資訊将并入現有行。 Fill 方法通過檢查 DataSet 中行的主鍵值以及 SelectCommand 傳回的行來确定是要添加新行還是更新現有行。 如果 Fill 方法遇到 DataSet 中某行的主鍵值與 SelectCommand 傳回結果中某行的主鍵值相比對,則它将用 SelectCommand 傳回的行中的資訊更新現有行,并将現有行的 RowState 設定為 Unchanged。 如果 SelectCommand 傳回的行所具有的主鍵值與 DataSet 中行的任何主鍵值都不比對,則 Fill 方法将添加 RowState 為 Unchanged 的新行。
![]() |
---|
如果 SelectCommand 傳回 OUTER JOIN 的結果,則 DataAdapter 不會為生成的 DataTable 設定 PrimaryKey 值。 您必須自己定義 PrimaryKey 以確定正确解析重複行。 有關更多資訊,請參見定義主鍵 (ADO.NET)。 |
若要處理在調用 Update方法時可能發生的異常,可以使用 RowUpdated 事件響應更新行時發生的錯誤(請參見處理 DataAdapter 事件 (ADO.NET)),也可以在調用 Update 之前将 DataAdapter.ContinueUpdateOnError 設定為 true,并在更新完成後響應特定行的 RowError 屬性中存儲的錯誤資訊(請參見行錯誤資訊)。
注意 對 DataSet、DataTable 或 DataRow 調用 AcceptChanges 将導緻 DataRow 的所有 Original 值被 DataRow 的 Current 值覆寫。 如果修改了唯一辨別該行的字段值,則在調用 AcceptChanges 後,Original 值将不再比對資料源中的值。 在調用 DataAdapter 的 Update 方法期間會對每一行自動調用 AcceptChanges。 在調用 Update 方法期間,通過先将 DataAdapter 的 AcceptChangesDuringUpdate 屬性設定為 false,或為 RowUpdated 事件建立一個事件處理程式并将 Status 設定為 SkipCurrentRow,可以保留原始值。 有關更多資訊,請參見合并資料集内容 (ADO.NET)和處理 DataAdapter 事件 (ADO.NET)。
示例
下面的示例示範如何通過顯式設定 DataAdapter 的 UpdateCommand 并調用其 Update 方法對已修改行的執行更新。 請注意,在 UPDATE 語句的 WHERE 子句中指定的參數設定為使用 SourceColumn 的 Original 值。 這一點很重要,因為 Current 值可能已被修改,可能會不比對資料源中的值。 Original 值是用于從資料源填充 DataTable 的值。
Visual Basic 複制代碼
Private Sub AdapterUpdate(ByVal connectionString As String)
Using connection As SqlConnection = New SqlConnection( _
connectionString)
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT CategoryID, CategoryName FROM dbo.Categories", _
connection)
adapter.UpdateCommand = New SqlCommand( _
"UPDATE Categories SET CategoryName = @CategoryName " & _
"WHERE CategoryID = @CategoryID", connection)
adapter.UpdateCommand.Parameters.Add( _
"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")
Dim parameter As SqlParameter = _
adapter.UpdateCommand.Parameters.Add( _
"@CategoryID", SqlDbType.Int)
parameter.SourceColumn = "CategoryID"
parameter.SourceVersion = DataRowVersion.Original
Dim categoryTable As New DataTable
adapter.Fill(categoryTable)
Dim categoryRow As DataRow = categoryTable.Rows(0)
categoryRow("CategoryName") = "New Beverages"
adapter.Update(categoryTable)
Console.WriteLine("Rows after update.")
Dim row As DataRow
For Each row In categoryTable.Rows
Console.WriteLine("{0}: {1}", row(0), row(1))
Next
End Using
End Sub
C# 複制代碼
private static void AdapterUpdate(string connectionString)
{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlDataAdapter dataAdpater = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM Categories",
connection);
dataAdpater.UpdateCommand = new SqlCommand(
"UPDATE Categories SET CategoryName = @CategoryName " +
"WHERE CategoryID = @CategoryID", connection);
dataAdpater.UpdateCommand.Parameters.Add(
"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");
SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
"@CategoryID", SqlDbType.Int);
parameter.SourceColumn = "CategoryID";
parameter.SourceVersion = DataRowVersion.Original;
DataTable categoryTable = new DataTable();
dataAdpater.Fill(categoryTable);
DataRow categoryRow = categoryTable.Rows[0];
categoryRow["CategoryName"] = "New Beverages";
dataAdpater.Update(categoryTable);
Console.WriteLine("Rows after update.");
foreach (DataRow row in categoryTable.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}
AutoIncrement 列
如果資料源中的表具有自動遞增列,則可以通過以下方式填充 DataSet 中的列:作為存儲過程的輸出參數傳回自動遞增值并将其映射到表中的一列、傳回由存儲過程或 SQL 語句傳回的結果集第一行中的自動遞增值或者使用 DataAdapter 的 RowUpdated 事件來執行其他 SELECT 語句。 有關更多資訊和示例,請參見檢索辨別或 Autonumber 值 (ADO.NET)。
插入、更新和删除的排序
在許多情況下,以何種順序向資料源發送通過 DataSet 所做的更改是非常重要的。 例如,如果更新了現有行的主鍵值,并且添加了以新主鍵值作為外鍵的新行,則務必要在處理插入之前處理更新。
可以使用 DataTable 的 Select 方法來傳回僅引用具有特定 RowState 的 DataRow 數組。 然後可以将傳回的 DataRow 數組傳遞給 DataAdapter 的 Update 方法來處理已修改的行。 通過指定要更新的行的子集,可以控制處理插入、更新和删除的順序。
示例
例如,以下代碼確定首先處理表中已删除的行,然後處理已更新的行,然後處理已插入的行。
Visual Basic 複制代碼
Dim table As DataTable = dataSet.Tables("Customers")
' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
DataViewRowState.Deleted))
' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
DataViewRowState.ModifiedCurrent))
' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
DataViewRowState.Added))
C# 複制代碼
DataTable table = dataSet.Tables["Customers"];
// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));
// Next process updates.
adapter.Update(table.Select(null, null,
DataViewRowState.ModifiedCurrent));
// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));
請參見
概念
行狀态與行版本 AcceptChanges 和 RejectChanges 合并資料集内容 (ADO.NET) 檢索辨別或 Autonumber 值 (ADO.NET)
其他資源
DataAdapter 和 DataReader (ADO.NET)