在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
当两个用户同时访问一个页面,一个用户可能更新的是另一个用户已经更改或删除的记录,这就是并发! 并发控制策略 Ø 什么都不做 –如果并发用户修改的是同一条记录,让最后提交的结果生效(默认的行为) 保守式并发较少使用,因为锁定的人离开,其他人就不能更改,使用保守式并发控制的地方,相应地会作一个时间限制,如果到达这个时间限制,则取消锁定。 开放式并发原理当在一个可编辑的GridView里点击编辑按钮时,该记录的值从数据库中读取出来并显示在TextBox和其他Web控件中。这些原始的值保存在GridView里。 并发控制之有无使用开放式并发和不使用并发控制的UPDATE 和 DELETE查询之间有什么不同,
DELETE FROM [Products]
WHERE (([ProductID] = @Original_ProductID) AND ([ProductName] = @Original_ProductName) AND ((@IsNull_SupplierID = 1 AND [SupplierID] IS NULL) OR ([SupplierID] = @Original_SupplierID)) AND ((@IsNull_CategoryID = 1 AND [CategoryID] IS NULL) OR ([CategoryID] = @Original_CategoryID)) AND ((@IsNull_QuantityPerUnit = 1 AND [QuantityPerUnit] IS NULL) OR ([QuantityPerUnit] = @Original_QuantityPerUnit)) AND ((@IsNull_UnitPrice = 1 AND [UnitPrice] IS NULL) OR ([UnitPrice] = @Original_UnitPrice)) AND ((@IsNull_UnitsInStock = 1 AND [UnitsInStock] IS NULL) OR ([UnitsInStock] = @Original_UnitsInStock)) AND ((@IsNull_UnitsOnOrder = 1 AND [UnitsOnOrder] IS NULL) OR ([UnitsOnOrder] = @Original_UnitsOnOrder)) AND ((@IsNull_ReorderLevel = 1 AND [ReorderLevel] IS NULL) OR ([ReorderLevel] = @Original_ReorderLevel)) AND ([Discontinued] = @Original_Discontinued)) 红色[ProductName]是数据库中值,绿色@Original_ProductID是GridView中原始值。
.NET创建的DAL code,
this.Adapter.DeleteCommand.Parameters[0].Value = ((int)(Original_ProductID)); ... if ((Original_SupplierID.HasValue == true)) { this.Adapter.DeleteCommand.Parameters[2].Value = ((object)(0)); //有值就置IsNull_SupplierID为0, this.Adapter.DeleteCommand.Parameters[3].Value = ((int)(Original_SupplierID.Value)); } else { this.Adapter.DeleteCommand.Parameters[2].Value = ((object)(1)); //无值就置为1 this.Adapter.DeleteCommand.Parameters[3].Value = global::System.DBNull.Value; } try { int returnValue = this.Adapter.DeleteCommand.ExecuteNonQuery(); return returnValue; } 不使用并发控制的DAL的Products TableAdapter所使用的DELETE语句则简单得多:
DELETE FROM [Products] WHERE (([ProductID] = @Original_ProductID))
相应的.NET DAL Code也简单
public virtual int Delete(int Original_ProductID) {
this.Adapter.DeleteCommand.Parameters[0].Value = ((int)(Original_ProductID)); global::System.Data.ConnectionState previousConnectionState = this.Adapter.DeleteCommand.Connection.State; if (((this.Adapter.DeleteCommand.Connection.State & global::System.Data.ConnectionState.Open) != global::System.Data.ConnectionState.Open)) { this.Adapter.DeleteCommand.Connection.Open(); } try { int returnValue = this.Adapter.DeleteCommand.ExecuteNonQuery(); return returnValue; } finally { if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) { this.Adapter.DeleteCommand.Connection.Close(); } } } Update方法之区别ProductsBLL的Update方法主要有三步:
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool Updateproduct(string productName, decimal? unitPrice, short? unitsInStock, int productID) { //(1) 使用TableAdapter的GetProductByProductID(productID)方法读取当前数据库中的产品信息到ProductRow实例 Northwind.ProductsDataTable products = ProductsAdapter.GetProductByProductID(productID); if (products.Count == 0) { return false; } Northwind.ProductsRow product = products[0]; //(2) Assign the new values to the ProductRow instance product.ProductName = productName; if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value; if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value; //(3) 调用TableAdapter的Update方法,传入该ProductRow实例 int rowAffected = ProductsAdapter.Update(product); return rowAffected == 1; } 相应的ProductsOptimisticConcurrencyBLL类中Update方法:
1protected void AssignAllProductValues(NorthwindOptimisticConcurrency.ProductsOptimisticConcurrencyRow product,
2 string productName, int? supplierID, int? categoryID, string quantityPerUnit, 3 decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, 4 bool discontinued) 5 STEP 3: Accept the changes, // ProductsOptimisticConcurrencyRow的AcceptChanges()方法 告诉DataRow,现在的值就是Original value 45 product.AcceptChanges(); 46 47 // STEP 4: Assign the new values to the product instance 48 AssignAllProductValues(product, productName, supplierID, categoryID, quantityPerUnit, unitPrice, 49 unitsInStock, unitsOnOrder, reorderLevel, discontinued); 50 51 // STEP 5: Update the product record 52 int rowsAffected = Adapter.Update(product); 53 54 // Return true if precisely one row was updated, otherwise false 55 return rowsAffected == 1; 56} 57
1. ObjectDataSource的OldValuesParameterFormatString属性的值是original_{0}。 2. 为了ObjectDataSource能够正确地将原始值传送到BLL方法, 3. 因为Delete方法不仅仅接受ProductID参数,所以,会遇到一些错误
1<ItemTemplate>
2 <asp:Label ID="DummyUnitPrice" runat="server" Text='<%# Bind("UnitPrice") %>' Visible="false"></asp:Label> 3 <asp:Label ID="Label4" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:Label> 4</ItemTemplate> Update方法也一样,添加Dummy控件
1<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
2 <EditItemTemplate> 3 4 </EditItemTemplate> 5 <ItemTemplate> 6 <asp:Label ID="DummyCategoryID" runat="server" Text='<%# Bind("CategoryID") %>' Visible="False"></asp:Label> 7 <asp:Label ID="Label2" runat="server" Text='<%# Eval("CategoryName") %>'></asp:Label> 8 </ItemTemplate> 9</asp:TemplateField> 10<asp:TemplateField HeaderText="Supplier" SortExpression="SupplierName"> 11 <EditItemTemplate> 12 13 </EditItemTemplate> 14 <ItemTemplate> 15 <asp:Label ID="DummySupplierID" runat="server" Text='<%# Bind("SupplierID") %>' Visible="False"></asp:Label> 16 <asp:Label ID="Label3" runat="server" Text='<%# Eval("SupplierName") %>'></asp:Label> 17 </ItemTemplate> 18</asp:TemplateField> 19
捕获ConCurrency
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; // OPTIONAL: Rebind the data to the GridView and keep it in edit mode //ProductsGrid.DataBind(); //e.KeepInEditMode = true; } } }
注意,如果是更新时,其他人把这条记录删除,这里不会捕获
protected void ProductsOptimisticConcurrencyDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{ if (e.ReturnValue != null && e.ReturnValue is bool) { bool updateReturnValue = (bool)e.ReturnValue; if (updateReturnValue == false) { // No row was updated, display the warning message UpdateLostMessage.Visible = true; } } }
|
请发表评论