为演示更新一批记录时事务的作用,我们将创建一个用户界面来将所有产品用一个GridView控件显示出来,并包含一个Button Web控件。当点击该按钮时为product重新赋值一个有效的CategoryID值。具体来说,对头几个products分配一个有效的CategoryID值;而剩下的分配一个无效的(non-existent)CategoryID值,当我们试图对这样的一个product——其CategoryID值与现有的category的CategoryID不匹配——进行更新时,将违反外键约束,进而抛出一个异常.在本文的示例里你将看到,在使用事务时,当违反外键约束抛出一个异常时将导致前面的正确分配CategoryID值的操作产生回滚.如果不使用事务的话,这些正确的操作将执行成功.
首先,打开BatchData文件夹里的Transactions.aspx页面,从工具箱拖一个GridView控件到页面。设置其ID为Products,从其智能标签里将其绑定到一个名为ProductsDataSource的ObjectDataSource控件,设置该控件调用ProductsBLL class类的GetProducts()方法。由于该GridView是“只读”的,在UPDATE, INSERT, 和DELETE标签里选“(None)”,点完成。
图5:设置ObjectDataSource使用ProductsBLL Class类的GetProducts方法
图6:在UPDATE, INSERT, 和DELETE标签里选“(None)”
完成设置后,Visual Studio将自动的添加BoundFields以及一个CheckBoxField,删除ProductID, ProductName, CategoryID,和CategoryName以外的其它列;并且分别将ProductName 和 CategoryName列的HeaderText属性重命名为“Product” 和 “Category”.在智能标签里启用“分页”功能.做完这些修改后,GridView 和 ObjectDataSource控件的声明代码看起来应该和下面的差不多:
<asp:GridView runat="server" AllowPaging="True" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ProductsDataSource"> <Columns> <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False" ReadOnly="True" SortExpression="ProductID" /> <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" /> <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" /> <asp:BoundField DataField="CategoryName" HeaderText="Category" SortExpression="CategoryName" /> </Columns> </asp:GridView> <asp:ObjectDataSource runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts" TypeName="ProductsBLL"> </asp:ObjectDataSource>
然后,在GridView控件上添加3个Button Web控件,设置第一个按钮的Text属性 为“Refresh Grid”;第二个按钮的Text属性为“Modify Categories (WITH TRANSACTION)”;第三个按钮的Text属性为“Modify Categories (WITHOUT TRANSACTION)”.
<p> <asp:Button runat="server" Text="Refresh Grid" /> </p> <p> <asp:Button runat="server" Text="Modify Categories (WITH TRANSACTION)" /> </p> <p> <asp:Button runat="server" Text="Modify Categories (WITHOUT TRANSACTION)" /> </p>
此时,在Visual Studio的设计模式里,界面看起来和下面的截屏差不多:
图7:页面包含一个GridView控件和三个Button Web控件
为这3个按钮的Click events事件创建事件处理器,如下:
protected void RefreshGrid_Click(object sender, EventArgs e) { Products.DataBind(); } protected void ModifyCategoriesWithTransaction_Click(object sender, EventArgs e) { // Get the set of products ProductsBLL productsAPI = new ProductsBLL(); Northwind.ProductsDataTable products = productsAPI.GetProducts(); // Update each product's CategoryID foreach (Northwind.ProductsRow product in products) { product.CategoryID = product.ProductID; } // Update the data using a transaction productsAPI.UpdateWithTransaction(products); // Refresh the Grid Products.DataBind(); } protected void ModifyCategoriesWithoutTransaction_Click(object sender, EventArgs e) { // Get the set of products ProductsBLL productsAPI = new ProductsBLL(); Northwind.ProductsDataTable products = productsAPI.GetProducts(); // Update each product's CategoryID foreach (Northwind.ProductsRow product in products) { product.CategoryID = product.ProductID; } // Update the data WITHOUT using a transaction NorthwindTableAdapters.ProductsTableAdapter productsAdapter = new NorthwindTableAdapters.ProductsTableAdapter(); productsAdapter.Update(products); // Refresh the Grid Products.DataBind(); }
refresh按钮的Click事件处理器仅仅调用Products GridView的DataBind方法将数据重新绑定到ridView控件.