DataAdapter 的 [b]Update[/b] 方法可调用来将 [b]DataSet[/b] 中的更改解析回数据源。与 [b]Fill[/b] 方法类似,[b]Update[/b] 方法将 [b]DataSet[/b] 的实例和可选的 [b]DataTable[/b] 对象或 [b]DataTable[/b] 名称用作参数。[b]DataSet[/b] 实例是包含已作出的更改的 [b]DataSet[/b],而 [b]DataTable[/b] 标识从其中检索更改的表。
当调用 [b]Update[/b] 方法时,[b]DataAdapter[/b] 将分析已作出的更改并执行相应的命令(INSERT、UPDATE 或 DELETE)。当 [b]DataAdapter[/b] 遇到对 [b]DataRow[/b] 的更改时,它将使用 [b]InsertCommand[/b]、[b]UpdateCommand[/b] 或 [b]DeleteCommand[/b] 来处理该更改。这样,您就可以通过在设计时指定命令语法并在可能时通过使用存储过程来尽量提高 ADO.NET 应用程序的性能。在调用 [b]Update[/b] 之前,必须显式设置这些命令。如果调用了 [b]Update[/b] 但不存在用于特定更新的相应命令(例如,不存在用于已删除行的 [b]DeleteCommand[/b]),则将引发异常。
[b]Command[/b] 参数可用于为 [b]DataSet[/b] 中每个已修改行的 SQL 语句或存储过程指定输入和输出值。有关更多信息,请参阅[url=http://software.it168.com/manual/ado.net/4-2-d.htm][color=#0066cc]将参数用于 DataAdapter[/color][/url]。
如果 [b]DataTable[/b] 映射到单个数据库表或从单个数据库表生成,则可以利用 [b]CommandBuilder[/b] 对象自动生成 [b]DataAdapter [/b]的 [b]DeleteCommand[/b]、[b]InsertCommand[/b] 和 [b]UpdateCommand[/b]。有关更多信息,请参阅[url=http://software.it168.com/manual/ado.net/4-2-f.htm][color=#0066cc]自动生成的命令[/color][/url]。
[b]Update[/b] 方法会将更改解析回数据源,但是自上次填充 [b]DataSet[/b] 以来,其他客户端可能已修改了数据源中的数据。若要使用当前数据刷新 [b]DataSet[/b],请再次使用 [b]DataAdapter[/b] 填充 ([b]Fill)[/b] [b]DataSet[/b]。新行将添加到该表中,更新的信息将并入现有行。
若要处理可能在 [b]Update[/b] 操作过程中发生的异常,可以使用 [b]RowUpdated[/b] 事件在这些异常发生时响应行更新错误(请参阅[url=http://software.it168.com/manual/ado.net/4-2-g.htm][color=#0066cc]使用 DataAdapter 事件[/color][/url]),或者可以在调用 [b]Update[/b] 之前将 [b]DataAdapter.ContinueUpdateOnError[/b] 设置为 [b]true[/b],然后在 [b]Update[/b] 完成时响应存储在特定行的 [b]RowError[/b] 属性中的错误信息(请参阅添加和读取行错误信息)。
[indent][b]注意[/b] 如果对 [b]DataSet[/b]、[b]DataTable[/b] 或 [b]DataRow[/b] 调用 [b]AcceptChanges[/b],则将使某 [b]DataRow[/b] 的所有 [b]Original[/b] 值被该 [b]DataRow[/b] 的 [b]Current[/b] 值改写。如果已修改将该行标识为唯一行的字段值,那么当调用 [b]AcceptChanges[/b] 后,[b]Original[/b] 值将不再匹配数据源中的值。 [/indent]以下示例演示如何通过显式设置 [b]DataAdapter[/b] 的 [b]UpdateCommand[/b] 来执行对已修改行的更新。请注意,在 UPDATE 语句的 WHERE 子句中指定的参数设置为使用 [b]SourceColumn[/b] 的 [b]Original[/b] 值。这一点很重要,因为 [b]Current[/b] 值可能已被修改,并且可能不匹配数据源中的值。[b]Original[/b] 值是曾用来从数据源填充 [b]DataTable[/b] 的值。
SqlClient
[Visual Basic]
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
[Visual Basic]
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);
自动递增列
如果来自数据源的表包含自动递增列,则可以使用由数据源生成的值填充 [b]DataSet[/b] 中的列,方法是通过以存储过程输出参数的形式返回自动递增值并将其映射到表中的一列,或者使用 [b]DataAdapter[/b] 的 [b]RowUpdated[/b] 事件。有关示例,请参阅检索“标识”或“自动编号”值。
但是,[b]DataSet[/b] 中的值可能会与数据源中的值不同步并导致意外的行为。例如,请考虑一个包含自动递增主键列 [font=新宋体]CustomerID[/font] 的表。如果在该 [b]DataSet[/b] 中添加两个新客户,它们将收到自动递增的 [font=新宋体]CustomerId[/font] 值 [font=新宋体]1[/font] 和 [font=新宋体]2[/font]。在向 [b]DataAdapter [/b]的 [b]Update[/b] 方法传递第二个客户行时,新添加的行会收到数据源中的自动递增 [font=新宋体]CustomerID[/font] 值 [font=新宋体]1[/font],该值与 [b]DataSet[/b] 中的值 [font=新宋体]2[/font] 不匹配。当 [b]DataAdapter[/b] 使用返回值填充 [b]DataSet[/b] 中的行时,由于第一个客户行的 [font=新宋体]CustomerID[/font] 已经是 [font=新宋体]1[/font],因此将发生约束冲突。
为了避免这种行为,建议在使用数据源中的自动递增列和 [b]DataSet[/b] 中的自动递增列时,在 [b]DataSet[/b] 中创建 [b]AutoIncrementStep[/b] 为 -1 且 [b]AutoIncrementSeed[/b] 为 0 的列,并确保数据源生成从 1 开始并以正步长值递增的自动递增标识值。这样,[b]DataSet[/b] 将为自动递增值生成负数,这些负数不会与数据源所生成的正自动递增值发生冲突。另一种方法是使用 [b]Guid[/b] 类型的列而不是自动递增列。生成 [b]Guid[/b] 值的算法在 [b]DataSet[/b] 中生成的 [b]Guid[/b] 从不会与数据源生成的 [b]Guid[/b] 相同。有关定义 [b]DataTable[/b] 中的列的更多信息,请参阅定义数据表的架构。
插入、更新和删除的排序
在许多情况下,以何种顺序向数据源发送通过 [b]DataSet[/b] 作出的更改是相当重要的。例如,如果已更新现有行的主键值并且添加了具有新主键值的新行,则务必要在处理插入之前处理更新。
可以使用 [b]DataTable[/b] 的 [b]Select[/b] 方法来返回仅引用具有特定 [b]RowState[/b] 的 [b]DataRow[/b] 数组。然后可以将返回的 [b]DataRow[/b] 数组传递到 [b]DataAdapter[/b] 的 [b]Update[/b] 方法来处理已修改的行。通过指定要更新的行的子集,可以控制处理插入、更新和删除的顺序。
例如,以下代码确保首先处理表中已删除的行,然后处理已更新的行,然后处理已插入的行。
[Visual Basic]
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));
的 [b]Update[/b] 方法可调用来将 [b]DataSet[/b] 中的更改解析回数据源。与 [b]Fill[/b] 方法类似,[b]Update[/b] 方法将 [b]DataSet[/b] 的实例和可选的 [b]DataTable[/b] 对象或 [b]DataTable[/b] 名称用作参数。[b]DataSet[/b] 实例是包含已作出的更改的 [b]DataSet[/b],而 [b]DataTable[/b] 标识从其中检索更改的表。