在某些情况下,我们想确保在进行一系列的改动时引入原子数(atomicity).为此,我们必须手动扩展TableAdapter,通过添加一些新的方法将InsertCommand, UpdateCommand, 和DeleteCommands命令置于事务之下.在第一章《创建一个数据访问层》里,我们考察了使用部分类(partial classes)对强类型数据集(Typed DataSet)里的DataTable的函数进行扩充.该技术同样适用于TableAdapter.
强类型数据集Northwind.xsd位于App_Code文件夹的DAL子文件夹里.在DAL文件夹里再创建一个名为TransactionSupport的子文件夹,再在里面添加一个新类,名为ProductsTableAdapter.TransactionSupport.cs (见图4).该类包含ProductsTableAdapter的使用事务的方法.
图4:创建一个名为TransactionSupport的新文件夹并添加一个名为ProductsTableAdapter.TransactionSupport.cs的新类
在ProductsTableAdapter.TransactionSupport.cs文件里键入如下的代码:
using System; using System.Data; using System.Data.SqlClient; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; namespace NorthwindTableAdapters { public partial class ProductsTableAdapter { private SqlTransaction _transaction; private SqlTransaction Transaction { get { return this._transaction; } set { this._transaction = value; } } public void BeginTransaction() { // Open the connection, if needed if (this.Connection.State != ConnectionState.Open) this.Connection.Open(); // Create the transaction and assign it to the Transaction property this.Transaction = this.Connection.BeginTransaction(); // Attach the transaction to the Adapters foreach (SqlCommand command in this.CommandCollection) { command.Transaction = this.Transaction; } this.Adapter.InsertCommand.Transaction = this.Transaction; this.Adapter.UpdateCommand.Transaction = this.Transaction; this.Adapter.DeleteCommand.Transaction = this.Transaction; } public void CommitTransaction() { // Commit the transaction this.Transaction.Commit(); // Close the connection this.Connection.Close(); } public void RollbackTransaction() { // Rollback the transaction this.Transaction.Rollback(); // Close the connection this.Connection.Close(); } } }
类声明里的关键字partial向编译器表明代码里添加的成员(members)是添加到命名空间NorthwindTableAdapters里的ProductsTableAdapter class类.我们注意到在文件的顶部有一个using System.Data.SqlClient声明,这是因为TableAdapter被设置为使用SqlClient provider,在其内部使用一个SqlDataAdapter object对象来向数据库发出命令.因此,我们需要使用SqlTransaction class类来启动事务,然后提交或回滚事务.如果没有使用Microsoft SQL Server数据库的话,你需要调用恰当的provider.
这些方法被标记为public,我们可以在ProductsTableAdapter里,或数据访问层DAL的其它类,甚至是其它层比如业务逻辑层BLL来调用这些法.
BeginTransaction()方法打开了TableAdapter的内部的SqlConnection(如果需要的话), 开启事务并赋值给Transaction属性,并将事务分配(attache)给SqlDataAdapter的SqlCommand objects对象.CommitTransaction()和 RollbackTransaction()方法在关闭内部的Connection object对象前分别调用Transaction object对象的Commit 和 Rollback方法.
添加上述代码后,我们将在ProductsDataTable 或业务逻辑层BLL里添加方法以执行一系列的置于事务之下的命令. 下面的代码在Batch Update pattern模式里使用一个事务来更新一个ProductsDataTable instance实例.它调用BeginTransaction method方法来启动一个事务,然后用一个try...catch模块来发布数据更改命令.如果调用Adapter object对象的Update方法出现异常,那么将转到catch区域,对事务进行回滚.记得执行Batch Update pattern模式的Update方法将遍历ProductsDataTable里的所有行(rows),执行相应的InsertCommand, UpdateCommand, 和DeleteCommands命令.如果这些命令中的其中一个出现异常,事务将回滚,撤销在事务里的所做的更改.如果Update命令全部执行无异常,那么提交事务.
public int UpdateWithTransaction(Northwind.ProductsDataTable dataTable) { this.BeginTransaction(); try { // Perform the update on the DataTable int returnValue = this.Adapter.Update(dataTable); // If we reach here, no errors, so commit the transaction this.CommitTransaction(); return returnValue; } catch { // If we reach here, there was an error, so rollback the transaction this.RollbackTransaction(); throw; } }