正如我们在在ASP.NET页面中处理BLL/DAL异常 这一节里看过的那样,这样的异常可以在数据Web服务器控件的post级事件处理里被发现和排除。因此,我们需要创建一个GridView的RowUpdated事件的处理,它用来检测是否抛出了一个DBConcurrencyException异常。这个事件处理通过一个不同的分支区别更新过程中引发的其它异常,如下面的时间处理代码所示:
protected void ProductsGrid_RowUpdated(object sender, GridViewUpdatedEventArgs e) { if (e.Exception != null && e.Exception.InnerException != null) { if (e.Exception.InnerException is System.Data.DBConcurrencyException) { // Display the warning message and note that the // exception has been handled... UpdateConflictMessage.Visible = true; e.ExceptionHandled = true; } } }
面对一个DBConcurrencyException异常,该事件处理显示UpdateConflictMessage Label控件并且指出该异常已经被处理。正确地编写了这些代码后,当更新记录时发生了并发冲突,用户的更改会丢失,因为他们不能覆盖同时发生的另一个用户的更改。特别地,GridView回到预编辑幢白并且绑定到当前数据库中数据。这将在GridView的行中显示出别的用户的更改,而之前这些更改是看不见的。另外,UpdateConflictMessage Label控件将向用户说明发生了什么。图19详细展示了这一连串的事件。
图 19: 面对并发冲突,一个用户的更改丢失了
注意:作为另一种选择,与其让GridView回到预编辑状态,我们还不如让GridView停留在编辑状态,通过设置传入的GridViewUpdatedEventArgs对象的KeepInEditMode属性为true。如果你接受这种方法,那么,必须重新绑定数据到GridView(通过调用它的DataBind()方法)从而将其他用户更改后的值栽入到编辑界面。在这一节的可下载的代码里,RowUpdated事件处理里有这两行注悉掉的代码;仅仅需要启用这两行代码就可以让GridView在发生了并发冲突之后保留编辑模式。
响应删除时的并发冲突
对于直接发送到数据库的模式,面对并发冲突时并不会引发异常。然而,数据库语句不影响任何记录,因为WHERE子句不能匹配任何记录。所有在BLL里创建的修改数据的方法都被设计为返回一个布尔值指示它们是否正好影响了一条记录。因此,为了确定删除记录时是否发生了并发冲突,我们可以检查BLL的DeleteProduct方法的返回值。
BLL方法的返回值可以在ObjectDataSource的post级事件处理中通过传入事件处理的ObjectDataSourceStatusEventArgs对象的ReturnValue属性被检测。因为我们感兴趣的是判断从DeleteProduct方法返回的结果,我们需要创建一个ObjectDataSource的Deleted事件的事件处理程序。该ReturnValue属性是object类型的,并且如果在方法可以返回一个值之前引发了异常并且方法被中断的情况下,它的值也可能为null。所以,我们应该首先确保ReturnValue属性非空并是个布尔值。若能通过这个检查,如果ReturnValue是 false我们显示DeleteConflictMessage Label控件。可以通过下面的代码完成:
protected void ProductsOptimisticConcurrencyDataSource_Deleted( object sender, ObjectDataSourceStatusEventArgs e) { if (e.ReturnValue != null && e.ReturnValue is bool) { bool deleteReturnValue = (bool)e.ReturnValue; if (deleteReturnValue == false) { // No row was deleted, display the warning message DeleteConflictMessage.Visible = true; } } }
面对一个并发冲突,用户的删除请求会被取消。GridView被刷新,显示在用户载入页面跟点击删除按钮之间的时间里发生在该记录上面的更改。当发生这样的一个冲突,显示DeleteConflictMessage Label控件,说明发生了什么(见图20)。
图 20: 面对并发冲突,一个用户的删除请求被取消了
总结
并发冲突可能存在于所有允许多用户同时更新或删除数据的应用程序里。如果不解决这样的冲突,当两个用户同时更新同一条数据,无论谁最后得到“胜利”,都将覆盖掉另一个用户所做的更改。作为另一种选择,开发者可以实现开放式并发控制(optimistic concurrency control),或者保守式并发控制(pessimistic concurrency control)。开放式并发控制假定并发冲突很少发生,简单地否决一个会提起并发冲突的更新或者删除命名。保守式并发控制则假定并发冲突频繁地发生,简单地拒绝某个用户的更新或者删除命令是不可接受的。在保守式并发控制下,编辑一条记录涉及到锁定它,从而该记录被锁定时预防其他用户的修改或删除。