使用SQL Server触发器
为该公司开发顾客服务应用程序的人员已经处理好Joe更新顾客信息时接收到的DBConcurrencyException异常的代码,应用程序工作又得很好了--直到下午Sally试图输入一个订单为止。
Sally接到一个顾客的订单电话。该顾客信息已经在数据库中了,因此Sally使用订单的基本信息包括邮寄地址。接着她打开OrderDetails屏幕并给订单添加了两个项目。每个OrderDetail记录包括OrderID 、ProductID 、Quantity 和Price。订单填完后,Sally点击Place Order按钮把订单插入数据库。我通过为OrderDetail记录添加硬编码值简化了代码(如图3所示)。
订单成功地插入和数据库,但是Sally接到一个提示,显示一个项没有货了,订单不能在两周内发货。该顾客意识到包裹送达时他不在城里,就询问是否可以更改发货地址。Sally在使用Order Maintenance屏幕前已经更改了订单信息,因此她说乐于帮忙。她打开适当的屏幕并为该顾客改变发货地址。但是她点击Save Changes按钮时,看到了一个与Joe相似的错误对话框,应用程序崩溃了。
理解为什么产生DBConcurrencyException的关键在于下层数据库。回想图5中我在OrderDetail表上设置了一个触发器,所有的INSERTS、UPDATES和DELETES都将调用它。trg_UpdateOrderTotal通过计算Order中每个OrderDetail行的数量乘以价格更新订单的总价格。当Sally建立一个有两个项的订单时,应用程序首先向Orders中插入一个新行,接着向OrderDetail插入两个新行。在每个OrderDetail记录建立后,调用触发器更新Order记录的Total列。但是这个值只在数据库中产生并且不会传递到应用程序。实际上,图3中的代码没有指定Total,因为在图1的代码中已经指定了一个默认值。接着默认值0随着新的Orders记录传递进SQL Server,该值在订单建立时是正确的。数据库接着更新Total列,但是应用程序中的数据表仍然使用0作为订单总价。当Sally试图更新Order记录时,数据适配器认为Total列的值已经改变了并产生一个DBConcurrencyException异常。
这儿的陷阱是过去当Sally已经更新Order记录时,碰巧自从最后一次数据自动刷新发生后,她没有更新刚才建立的新订单。在建立每个订单30分钟内,dsAllData数据集对象被刷新,它将使用正确的合计值更新Orders数据表。任何在数据自动更新(或者应用程序重新启动)后作的更新将按预计的情形工作。
这个问题的解决方法与前面的问题相似:刷新用户看到的数据。但是我能够更主动,不是等待并发性异常发生。我能在建立OrderDetail记录后,自动刷新每一个Orders数据行。我能更改图3中的代码,使它包含一个UpdateRow程序的调用,在调用daOrderDetail的Update方法后指定Orders中的行。SQL Server将正常完成该触发器,但是你不能依赖它,因此开发者也许会添加一个时间延迟,这样触发器有足够的时间完成。
结论 ADO.NET数据集对象的不连接特性提供了很高的性能,也给应用程序带来了数据并发性类型的错误。了解这些错误怎样和为什么出现将允许你很好地捕捉和处理这种错误,给应用程序增加另一个层次的支持。这给用户维护下层数据的完整性更多的选择。伴随着应用程序进一步迁移到互联网和内部网,用户成倍增加,并发性问题的处理面临更大的挑战。ADO.NET为解决该问题提供了所有的必要工具。
查看本文来源