使用 DataAdapter 更新数据源 (ADO.NET)

来源:互联网 发布:广电网络客服电话绵阳 编辑:程序博客网 时间:2024/03/28 22:18

调用 DataAdapterUpdate 方法可以将 DataSet 中的更改解析回数据源。 Fill 方法类似,Update 方法将 DataSet 的实例和可选的 DataTable 对象或 DataTable 名称用作参数。 DataSet 实例是包含已做的更改的 DataSetDataTable 标识从其中检索这些更改的表。 如果未指定 DataTable,则使用 DataSet 中的第一个 DataTable

当调用 Update 方法时,DataAdapter 会分析已做的更改并执行相应的命令(INSERT、UPDATE 或 DELETE)。 DataAdapter 遇到对 DataRow 所做的更改时,它将使用 InsertCommandUpdateCommandDeleteCommand 来处理该更改。 这样,您就可以通过在设计时指定命令语法并在可能时通过使用存储过程来尽量提高 ADO.NET 应用程序的性能。 在调用 Update 之前,必须显式设置这些命令。 如果调用了 Update 但不存在用于特定更新的相应命令(例如,不存在用于已删除行的 DeleteCommand),则会引发异常。

说明说明

如果您要通过 SQL Server 存储过程使用 DataAdapter 来编辑或删除数据,请确保不要在存储过程定义中使用 SET NOCOUNT ON。 这将使返回的受影响的行数为零,DataAdapter 会将其解释为并发冲突。 在这种情况下,将引发 DBConcurrencyException

可以使用命令参数为 DataSet 中每个已修改的行指定 SQL 语句或存储过程的输入和输出值。 有关更多信息,请参见DataAdapter 参数 (ADO.NET)

说明说明

必须了解在 DataTable 中删除行和移除行之间的差异。 当调用 RemoveRemoveAt 方法时,会立即移除该行。 如果之后将 DataTableDataSet 传递给 DataAdapter 并调用 Update,则不会影响后端数据源中的任何相应行。 当您使用 Delete 方法时,该行仍将保留在 DataTable 中并会标记为删除。 如果之后将 DataTableDataSet 传递给 DataAdapter 并调用 Update,则会删除后端数据源中的相应行。

如果 DataTable 映射到单个数据库表或从单个数据库表生成,则可以利用 DbCommandBuilder 对象为 DataAdapter 自动生成 DeleteCommandInsertCommandUpdateCommand 对象。 有关更多信息,请参见使用 CommandBuilder 生成命令 (ADO.NET)

通过使用 DbCommand 对象的 UpdatedRowSource 属性,您可以在调用 DataAdapter 的 Update 方法后控制从数据源返回的值映射回 DataTable 的方式。 通过将 UpdatedRowSource 属性设置为 UpdateRowSource 枚举值之一,您可以控制是忽略由 DataAdapter 命令返回的输出参数还是将其应用于 DataSet 中已更改的行。 还可以指定是否将返回的第一行(如果存在)应用于 DataTable 中已更改的行。

下表说明 UpdateRowSource 枚举的不同值,并说明它们如何影响与 DataAdapter 一起使用的命令的行为。

UpdatedRowSource 枚举

说明

Both

输出参数和返回的结果集的第一行都可以映射到 DataSet 中已更改的行。

FirstReturnedRecord

只有返回的结果集的第一行中的数据才可以映射到 DataSet 中已更改的行。

None

忽略任何输出参数或返回的结果集中的行。

OutputParameters

只有输出参数才可以映射到 DataSet 中已更改的行。

Update 方法会将更改解析回数据源;但在上次填充 DataSet 后,其他客户端可能已修改了数据源中的数据。 若要使用当前数据刷新 DataSet,请使用 DataAdapterFill 方法。 新行将添加到该表中,更新的信息将并入现有行。 Fill 方法通过检查 DataSet 中行的主键值以及 SelectCommand 返回的行来确定是要添加新行还是更新现有行。 如果 Fill 方法遇到 DataSet 中某行的主键值与 SelectCommand 返回结果中某行的主键值相匹配,则它将用 SelectCommand 返回的行中的信息更新现有行,并将现有行的 RowState 设置为 Unchanged 如果 SelectCommand 返回的行所具有的主键值与 DataSet 中行的任何主键值都不匹配,则 Fill 方法将添加 RowStateUnchanged 的新行。

说明说明

如果 SelectCommand 返回 OUTER JOIN 的结果,则 DataAdapter 不会为生成的 DataTable 设置 PrimaryKey 值。 您必须自己定义 PrimaryKey 以确保正确解析重复行。 有关更多信息,请参见定义主键 (ADO.NET)

若要处理在调用 Update方法时可能发生的异常,可以使用 RowUpdated 事件响应更新行时发生的错误(请参见处理 DataAdapter 事件 (ADO.NET)),也可以在调用 Update 之前将 DataAdapter.ContinueUpdateOnError 设置为 true,并在更新完成后响应特定行的 RowError 属性中存储的错误信息(请参见行错误信息)。

注意   对 DataSetDataTableDataRow 调用 AcceptChanges 将导致 DataRow 的所有 Original 值被 DataRowCurrent 值覆盖。 如果修改了唯一标识该行的字段值,则在调用 AcceptChanges 后,Original 值将不再匹配数据源中的值。 在调用 DataAdapter 的 Update 方法期间会对每一行自动调用 AcceptChanges 在调用 Update 方法期间,通过先将 DataAdapterAcceptChangesDuringUpdate 属性设置为 false,或为 RowUpdated 事件创建一个事件处理程序并将 Status 设置为 SkipCurrentRow,可以保留原始值。 有关更多信息,请参见合并数据集内容 (ADO.NET)处理 DataAdapter 事件 (ADO.NET)

下面的示例演示如何通过显式设置 DataAdapterUpdateCommand 并调用其 Update 方法对已修改行的执行更新。 请注意,在 UPDATE 语句的 WHERE 子句中指定的参数设置为使用 SourceColumnOriginal 值。 这一点很重要,因为 Current 值可能已被修改,可能会不匹配数据源中的值。 Original 值是用于从数据源填充 DataTable 的值。

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]);            }        }    }}

如果数据源中的表具有自动递增列,则可以通过以下方式填充 DataSet 中的列:作为存储过程的输出参数返回自动递增值并将其映射到表中的一列、返回由存储过程或 SQL 语句返回的结果集第一行中的自动递增值或者使用 DataAdapterRowUpdated 事件来执行其他 SELECT 语句。 有关更多信息和示例,请参见检索标识或 Autonumber 值 (ADO.NET)

在许多情况下,以何种顺序向数据源发送通过 DataSet 所做的更改是非常重要的。 例如,如果更新了现有行的主键值,并且添加了以新主键值作为外键的新行,则务必要在处理插入之前处理更新。

可以使用 DataTableSelect 方法来返回仅引用具有特定 RowStateDataRow 数组。 然后可以将返回的 DataRow 数组传递给 DataAdapterUpdate 方法来处理已修改的行。 通过指定要更新的行的子集,可以控制处理插入、更新和删除的顺序。

例如,以下代码确保首先处理表中已删除的行,然后处理已更新的行,然后处理已插入的行。

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)
原创粉丝点击