这个DBConcurrencyException异常仅当利用DAL的批量更新模式时会被抛出。直接发送到数据库的模式则不会引发异常,它仅仅会提示没有行受到影响。为了举例说明这个,两个浏览器窗口里的GridView都回到预编辑的状态。然后,在第一个窗口里,点击编辑按钮,把产品名称从“Chai”改为“Chai Tea”并点击更新。在第二个窗口里,点击产品“Chai”的删除按钮。点击删除按钮,页面会传,GridView调用ObjectDataSource的Delete()方法,然后ObjectDataSource调用ProductsOptimisticConcurrencyBLL类的DeleteProduct方法,传入原始的值。在第二个浏览器窗口里原始的ProductName值是“Chai Tea”,这个值与当前数据库中相应的ProductName值是不一致的。因此,发送到数据库的DELETE语句影响0行,因为数据库中没有记录能够满足WHERE子句。DeleteProduct方法返回false并且ObjectDataSource的数据重新绑定到GridView控件。
从最后一个用户的观点来看,在第二个浏览器窗口里点击了产品“Chai Tea”的删除按钮导致屏幕闪烁,恢复后该产品依旧在,虽然现在它的名称是“Chai”(在第一个浏览器窗口里修改了产品名称)。如果用户再次点击删除按钮,这次就能成功删除,因为GridView的原始的ProductName值(“Chai”)现在能够与数据库中相应的值匹配。在这些例子里,用户的体验跟理想的状况还有颇远的距离。显然我们在使用批量更新模式时不希望用户看到DBConcurrencyException异常生硬的详细信息。并且使用直接发送到数据库模式的行为也会让用户有些疑惑,因为用户操作失败了但是没有准确的提示说明为什么。
为了补救这两个小问题,我们可以在页面上放置一个Label服务器控件,它用来提供为什么更新或删除失败的说明。在批量更新模式,我们可以在GridView的post级事件处理里判定是否引发了一个DBConcurrencyException异常,显示必要的警告标签。对于直接发送到数据库的方法,我们可以检测BLL方法(它对一行或多行产生影响返回true,否则false)的返回值并显示必要的提示信息。
第六步: 添加提示信息并且在发生并发冲突时显示
当一个并发冲突出现时,展现出来的行为取决于是使用DAL的批量更新还是直接发送到数据库的模式。我们这一节的教程两种模式都用了,用批量更新模式实现修改,用直接发送到数据库的方式实现删除。首先,我们添加两个Label服务器控件到页面,它们用来解释更新或删除数据时出现的并发冲突。设置Label控件的Visible和EnableViewState属性为false;这意味一般情况下它们都是隐藏的,除非是那些特别的页面访问,在那里它们的Visible属性通过编码设置为true。
<asp:Label runat="server" Visible="False" EnableViewState="False" CssClass="Warning" Text="The record you attempted to delete has been modified by another user since you last visited this page. Your delete was cancelled to allow you to review the other user's changes and determine if you want to continue deleting this record." /> <asp:Label runat="server" Visible="False" EnableViewState="False" CssClass="Warning" Text="The record you attempted to update has been modified by another user since you started the update process. Your changes have been replaced with the current values. Please review the existing values and make any needed changes." />
在设置了它们的Visible、EnabledViewState和Text属性之外,我们还要把CssClass属性设置为Warning,这让标签显示大的、红色的、斜体、加粗的字体。这个CSS Warning 分类是在研究插入、更新和删除的关联事件这一节里添加到Styles.css并且定义好的。添加了这些标签之后,Visual Studio设计器里看起来应该类似于图18:
图 18: 两个Label控件添加到页面
这些Label服务器控件放置到适当的位置后,我们准备好检测当并发冲突发生时如何判定,在哪个时间点把适当的Label的Visible属性设置为true并显示提示信息。
更新时处理并发冲突
让我们首先看看当使用批量更新模式是如何处理并发冲突。因为批量更新模式下的这些冲突导致抛出一个DBConcurrencyException异常,我们需要在ASP.NET页面中添加代码来判定更新过程中出现的是否DBConcurrencyException异常。如果是,我们则显示一个信息向用户解释他们的更改没有被保存,由于别的用户在他开始编辑和点击更新按钮之间的时间里修改了同样的数据记录。