使用 dataadapter 和 dataset 更新数据库

dataadapter 的 update 方法可调用来将 dataset 中的更改解析回数据源。和 fill 方法类似,update 方法将 dataset 的实例和可选的 datatable 对象或 datatable 名称用作参数。dataset 实例是包含已作出的更改的 dataset,而 datatable 标识从其中检索更改的表。

当调用 update 方法时,dataadapter 将分析已作出的更改并执行相应的命令(insert、update 或 delete)。当 dataadapter 遇见对 datarow 的更改时,他将使用 insertcommand、updatecommand 或 deletecommand 来处理该更改。这样,你就能通过在设计时指定命令语法并在可能时通过使用存储过程来尽量提高 ado.net 应用程式的性能。在调用 update 之前,必须显式设置这些命令。如果调用了 update 但不存在用于特定更新的相应命令(例如,不存在用于已删除行的 deletecommand),则将引发异常。

command 参数可用于为 dataset 中每个已修改行的 sql 语句或存储过程指定输入和输出值。有关更多信息,请参阅将参数用于 dataadapter。

如果 datatable 映射到单个数据库表或从单个数据库表生成,则能利用 commandbuilder 对象自动生成 dataadapter 的 deletecommand、insertcommand 和 updatecommand。有关更多信息,请参阅自动生成的命令。

update 方法会将更改解析回数据源,不过自上次填充 dataset 以来,其他客户端可能已修改了数据源中的数据。若要使用当前数据刷新 dataset,请再次使用 dataadapter 填充 (fill) dataset。新行将添加到该表中,更新的信息将并入现有行。

若要处理可能在 update 操作过程中发生的异常,能使用 rowupdated 事件在这些异常发生时响应行更新错误(请参阅使用 dataadapter 事件),或能在调用 update 之前将 dataadapter.continueupdateonerror 设置为 true,然后在 update 完成时响应存储在特定行的 rowerror 属性中的错误信息(请参阅添加和读取行错误信息)。

注意 如果对 dataset、datatable 或 datarow 调用 acceptchanges,则将使某 datarow 的所有 original 值被该 datarow 的 current 值改写。如果已修改将该行标识为唯一行的字段值,那么当调用 acceptchanges 后,original 值将不再匹配数据源中的值。
以下示例演示怎么通过显式设置 dataadapter 的 updatecommand 来执行对已修改行的更新。请注意,在 update 语句的 where 子句中指定的参数设置为使用 sourcecolumn 的 original 值。这一点非常重要,因为 current 值可能已被修改,并且可能不匹配数据源中的值。original 值是曾用来从数据源填充 datatable 的值。

sqlclient
[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



自动递增列
如果来自数据源的表包含自动递增列,则能使用由数据源生成的值填充 dataset 中的列,方法是通过以存储过程输出参数的形式返回自动递增值并将其映射到表中的一列,或使用 dataadapter 的 rowupdated 事件。有关示例,请参阅检索“标识”或“自动编号”值。

不过,dataset 中的值可能会和数据源中的值不同步并导致意外的行为。例如,请考虑一个包含自动递增主键列 customerid 的表。如果在该 dataset 中添加两个新客户,他们将收到自动递增的 customerid 值 1 和 2。在向 dataadapter 的 update 方法传递第二个客户行时,新添加的行会收到数据源中的自动递增 customerid 值 1,该值和 dataset 中的值 2 不匹配。当 dataadapter 使用返回值填充 dataset 中的行时,由于第一个客户行的 customerid 已是 1,因此将发生约束冲突。

为了避免这种行为,建议在使用数据源中的自动递增列和 dataset 中的自动递增列时,在 dataset 中创建 autoincrementstep 为 -1 且 autoincrementseed 为 0 的列,并确保数据源生成从 1 开始并以正步长值递增的自动递增标识值。这样,dataset 将为自动递增值生成负数,这些负数不会和数据源所生成的正自动递增值发生冲突。另一种方法是使用 guid 类型的列而不是自动递增列。生成 guid 值的算法在 dataset 中生成的 guid 从不会和数据源生成的 guid 相同。有关定义 datatable 中的列的更多信息,请参阅定义数据表的架构。

插入、更新和删除的排序
在许多情况下,以何种顺序向数据源发送通过 dataset 作出的更改是相当重要的。例如,如果已更新现有行的主键值并且添加了具有新主键值的新行,则务必要在处理插入之前处理更新。

能使用 datatable 的 select 方法来返回仅引用具有特定 rowstate 的 datarow 数组。然后能将返回的 datarow 数组传递到 dataadapter 的 update 方法来处理已修改的行。通过指定要更新的行的子集,能控制处理插入、更新和删除的顺序。

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


[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));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值