该方法调用BLL层的GetProducts method方法,通过一个ProductsDataTable来获取所有的产品.然后遍历GridView控件的Rows collection集,该Rows collection集包含了GridView里每行所对应的GridViewRow instance实例。由于GridView里每页最多显示了10行,所以GridView控件的Rows collection集包含的条码最多不超过10条.
每行记录的ProductID来源于DataKeys collection集,并从ProductsDataTable里选出对应的ProductsRow.这4个TemplateField input控件的值赋值给ProductsRow instance实例的属性。当对ProductsDataTable更新完成后,又转到BLL业务逻辑层的UpdateWithTransaction method方法,就像我们在前面的教程看到的一样,该方法仅仅调用DAL数据访问层的UpdateWithTransaction方法.
本文使用的批更新策略是:将ProductsDataTable里对应于GridView里每行记录的所有row进行更新,不管用户有没有改动过产品信息.这种盲目的更改虽然执行起来没什么问题,但将会导致database table里出现多余的记录.在前面的第37章《DataList批量更新》里,我们考察里DataList控件的批更新界面,在那篇文章里我们使用饿代码只更新那些确实被用户改动过的记录.如果愿意的话,你可以使用37章的方法.
注意:当通过GridView的智能标签来绑定数据源时,Visual Studio会自动的将数据源的主键值指定为GridView的DataKeyNames属性.如果你没有通过GridView的智能标签来绑定ObjectDataSource的话,我们需要手工设置GridView控件DataKeyNames属性为“ProductID”, 以便通过DataKeys collection集来访问ProductID值.
BatchUpdate方法里的代码和BLL业务逻辑层里的UpdateProduct methods方法的代码很相似,主要的区别在于UpdateProduct methods方法仅仅获取一个单一的ProductRow instance实例.UpdateProducts methods方法里对ProductRow的属性赋值的代码与BatchUpdate方法里foreach循环里的代码是一模一样的.
最后,当点击任意一个“Update Products”按钮时,将调用BatchUpdate方法,为这2个按钮的Click events事件创建事件处理器,在里面添加如下的代码:
BatchUpdate(); ClientScript.RegisterStartupScript(this.GetType(), "message", "alert('The products have been updated.');", true);
以上代码首先调用BatchUpdate()方法;再使用ClientScript property属性来注入JavaScript,以显示一个messagebox,提示“The products have been updated.”
花几分钟测试代码.在浏览器的登录BatchUpdate.aspx页面,编辑几行记录,点任意一个“Update Products”按钮。假定输入无误,你会看到一个消息框显示“The products have been updated.”为了测试原子操作,你可以任意添加一个CHECK约束,比如不接受UnitPrice的值为“1234.56”。然后再登录BatchUpdate.aspx页面,编辑几行记录,确保设置其中的一条记录的UnitPrice值为“1234.56”. 当点“Update Products”按钮时,将会出错。结果是所有的操作回滚,回到原来的值.
另一种可供选择的BatchUpdate方法
上面我们探讨的BatchUpdate方法从BLL业务逻辑层的GetProducts方法获取所有的产品.
如果GridView没有启用分页的话,一切都很完美.如果启用了分页了呢?比如可能总共有几百、几千、几万条产品记录,而GridView里每页只显示了10条记录。在这种情况下,该方法获取了所有的记录,但只更新其中的10条记录,实在是难称完美.
面对这种情况,可以考虑使用下面的BatchUpdateAlternate代替:
private void BatchUpdateAlternate() { // Enumerate the GridView's Rows collection and create a ProductRow ProductsBLL productsAPI = new ProductsBLL(); Northwind.ProductsDataTable products = new Northwind.ProductsDataTable(); foreach (GridViewRow gvRow in ProductsGrid.Rows) { // Create a new ProductRow instance int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value); Northwind.ProductsDataTable currentProductDataTable = productsAPI.GetProductByProductID(productID); if (currentProductDataTable.Rows.Count > 0) { Northwind.ProductsRow product = currentProductDataTable[0]; // Programmatically access the form field elements in the // current GridViewRow TextBox productName = (TextBox)gvRow.FindControl("ProductName"); DropDownList categories = (DropDownList)gvRow.FindControl("Categories"); TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice"); CheckBox discontinued = (CheckBox)gvRow.FindControl("Discontinued"); // Assign the user-entered values to the current ProductRow product.ProductName = productName.Text.Trim(); if (categories.SelectedIndex == 0) product.SetCategoryIDNull(); else product.CategoryID = Convert.ToInt32(categories.SelectedValue); if (unitPrice.Text.Trim().Length == 0) product.SetUnitPriceNull(); else product.UnitPrice = Convert.ToDecimal(unitPrice.Text); product.Discontinued = discontinued.Checked; // Import the ProductRow into the products DataTable products.ImportRow(product); } } // Now have the BLL update the products data using a transaction productsAPI.UpdateProductsWithTransaction(products); }