正如之前注意到的,批量更新模式时用的TableAdapter的Update方法也有同样的方法声明为不管是否支持开放式并发。也就是,Update方法可以接受一个DataRow,一批DataRow,一个DataTable,或者一个类型化的数据集。正是因为DataTable在它的DataRow(s)里保留了从原始值到修改后的值这个变化的轨迹使这成为可能。当DAL生成它的UPDATE语句时,参数@original_ColumnName装入DataRow中的原始值,反之,参数@ColumnName装入DataRow中修改后的值。
在类ProductsBLL(我们最初使用的不支持开放式并发DAL的)里,当我们使用批量更新模式更新产品信息时,我们的代码执行的则是按顺序执行下列事件:
1.使用TableAdapter的GetProductByProductID(productID)方法读取当前数据库中的产品信息到ProductRow实例
2.在第1步里将新的值赋值到ProductRow实例
3.调用TableAdapter的Update方法,传入该ProductRow实例
这一连串的步骤,无论如何都不可能支持开放式并发,因为在第一步中产生的ProductRow是直接从数据库组装的,这意味着,DataRow中使用的原始值是当前存在于数据库中值,而并非开始编辑过程时绑定到GridView的值。相反地,当使用启用开放式并发的DAL,我们需要修改UpdateProduct方法的重载以使用下面这些步骤:
1.使用TableAdapter的GetProductByProductID(productID)方法读取当前数据库中的产品信息到ProductsOptimisticConcurrencyRow实例
2.在第1步里将原始 值赋值到ProductsOptimisticConcurrencyRow实例
3.调用ProductsOptimisticConcurrencyRow实例的AcceptChanges()方法,这指示DataRow目前这些值是“原始”的值
4.将新 的值赋值到ProductsOptimisticConcurrencyRow实例
5.调用TableAdapter的Update方法,传入该ProductsOptimisticConcurrencyRow实例
第1步读取当前数据库里指定产品记录的所有字段的值。对更新所有 产品字段的UpdateProduct的重载里,这一步是多余的(因为这些值在第2步中被改写),而对那些仅仅传入部分字段值的重载方法来说则是必要的。一旦原始值赋值到ProductsOptimisticConcurrencyRow实例,调用AcceptChanges()方法,这将当前DataRow中的值标记为原始值,这些值将用作UPDATE语句的@original_ColumnNam参数。然后,新的参数值被赋值到ProductsOptimisticConcurrencyRow,最后,调用Update方法,传入这个DataRow。
下面这些代码展示了重载方法UpdateProduct接受所有产品数据字段作为输入参数。虽然这里没有展示,实际上从本节教程下载的ProductsOptimisticConcurrencyBLL类里还包含了重载方法UpdateProduct,它仅仅接受产品名称和单价作为输入参数。
protected void AssignAllProductValues (NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow product, string productName, int? supplierID, int? categoryID, string quantityPerUnit, decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, bool discontinued) { product.ProductName = productName; if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value; if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value; if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit; if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value; if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value; if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value; if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value; product.Discontinued = discontinued; } [System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, true)] public bool UpdateProduct( // new parameter values string productName, int? supplierID, int? categoryID, string quantityPerUnit, decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, bool discontinued, int productID, // original parameter values string original_productName, int? original_supplierID, int? original_categoryID, string original_quantityPerUnit, decimal? original_unitPrice, short? original_unitsInStock, short? original_unitsOnOrder, short? original_reorderLevel, bool original_discontinued, int original_productID) { // STEP 1: Read in the current database product information NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyDataTable products = Adapter.GetProductByProductID(original_productID); if (products.Count == 0) // no matching record found, return false return false; NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow product = products[0]; // STEP 2: Assign the original values to the product instance AssignAllProductValues(product, original_productName, original_supplierID, original_categoryID, original_quantityPerUnit, original_unitPrice, original_unitsInStock, original_unitsOnOrder, original_reorderLevel, original_discontinued); // STEP 3: Accept the changes product.AcceptChanges(); // STEP 4: Assign the new values to the product instance AssignAllProductValues(product, productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued); // STEP 5: Update the product record int rowsAffected = Adapter.Update(product); // Return true if precisely one row was updated, otherwise false return rowsAffected == 1; }
第四步: 从ASP.NET页面把原始值和新值传入BLL 方法