当使用GridView、DetailsView或FormView控件的内建插入、编辑或删除特征时,在用户添加一条新记录或更新/删除一条现在记录的过程中发生了多个步骤。正如我们之前一节里所讨论的,在GridView中编辑一行时,保存(Update)和取消(Cancel)按钮将取代编辑(Edit)按钮,并且绑定列转换成TextBox。在用户更新了数据并点击保存按钮之后,下述步骤在回传时执行:
1.该GridView控件根据当前编辑行的唯一标识字段(通过DataKeyNames属性)组装它的ObjectDataSource的UpdateParameters参数,连同用户输入的值
2.该GridView控件调用它的ObjectDataSource的Update()方法,它转而调用潜在对象的适当的方法(ProductsDAL.UpdateProduct,我们之前一节里)
3.现在,这些隐含的数据,包含保存后的更改,被重新绑定到GridView控件
在这一连串的步骤里,触发了许多事件,这让我们可以创建事件处理程序从而在需要的地方增加自定义逻辑。例如,在第1步之前,触发GridView的事件。在这里,如果有什么validation错误我们可以取消更新请求。当调用Update()方法时,触发ObjectDataSource的Updating事件,提供了增加或自定义UpdateParameters的值的机会。在ObjectDataSource的潜在对象的方法完全执行后,触发ObjectDataSource的Updated事件。针对Updated事件的事件处理程序可以检查更新操作的相关详细信息,例如影响了多少行数据,或者是否引发了一个异常。最后,在第2步之后,GridView的RowUpdated事件触发;针对此事件的事件处理程序可以检查关于刚刚完成的更新操作的相关额外信息。
图1描述了使用GridView更新时这一系列连续的事件和步骤。图1里的这个事件模式不仅是在GridView的更新操作。从GridView、DetailsView或者FormView里插入、更新或者删除数据时,数据Web服务器控件和ObjectDataSource都会发生这一连串的pre-level和post-level的事件。
图1: 当在GridView里更新数据时,触发一连串的Pre-和Post-事件
在这一节里,我们将探讨使用这些事件从而扩展ASP.NET数据Web服务器控件的内建插入、更新和删除功能。我们也会看看如何自定义编辑界面从而仅仅更新部分产品字段。
第一步: 更新产品的ProductName和UnitPrice字段
在之前一节的编辑界面里,包含了产品的所有字段并且它们都不是只读的。如果我们从GridView中剔除一列(QuantityPerUnit),那么当更新时数据Web服务器控件就不会设置ObjectDataSource的QuantityPerUnit UpdateParameters的值。ObjectDataSource则传入一个null值到UpdateProduct这个业务逻辑层的方法,它将当前编辑的数据库记录的QuantityPerUnit字段更改为值。同样地,如果是一个必需的字段,例如ProductName,如果从编辑界面中剔除了,那么此更新将会失败并抛出一个“Column 'ProductName' does not allow nulls”异常。导致这一现象的原因是ObjectDataSource被配置为调用ProductsBLL类的UpdateProduct方法,它预期每一个产品字段都对应一个输入参数。因此,ObjectDataSource的UpdateParameters集合包含了该方法的每一个输入参数。
如果我们希望提供一个允许最终用户仅仅可以更新部分字段的数据Web服务器控件,那么我们需要在ObjectDataSource的Updating事件处理程序中编程设置缺失的UpdateParameters值,或者创建并调用一个预期部分字段的BLL方法。让我们在接下来的步骤中探讨。
特别地,让我们创建一个在一个可编辑的GridView中仅显示ProductName和UnitPrice字段的页面。这个GridView的编辑界面将仅仅允许用户更新两个显示的字段,ProductName和UnitPrice 。因为这个编辑界面仅仅提供产品的部分字段,我们需要创建一个ObjectDataSource,它使用现有的BLL的UpdateProduct方法并在Updating事件处理程序中编程设置产品的缺少的字段的值,或者我们需要创建一个新的BLL方法,它仅接受那些在GridView中已经定义的部分字段。在这一节里,我们使用后者,创建一个UpdateProduct方法的重载,它提取3个输入参数:productName、unitPrice和productID:
[System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, false)] public bool UpdateProduct(string productName, decimal? unitPrice, int productID) { Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID); if (products.Count == 0) // no matching record found, return false return false; Northwind.ProductsRow product = products[0]; product.ProductName = productName; if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value; // Update the product record int rowsAffected = Adapter.Update(product); // Return true if precisely one row was updated, otherwise false return rowsAffected == 1; }