在DataAdapter中開啓事務

ADO.NET 2.0中引入了strong typed table adapter,強化了strong typed dataset的設計視圖,使用非常方便,但是在實際運用當中,還是遇到了一些麻煩,比如怎麼在多個table adapter之間開啓事務,由於table adapter自身沒有提供事務功能,而且它的connection對象默認是private,所以要實現事務稍微有些麻煩,目前的解決方法大概如下幾種最簡單的一個方法就是使用transaction scope,如下:
using (TransactionScope ts = new TransactionScope())
            {
                
//do something here
                ts.Complete();
            }
但該方法有個缺點,需要開啓135端口,還要配置MS DTC,在某些不能隨便開啓端口的環境下就不能使用該方法。
  方法二:將connectionmodifier屬性改爲public,然後操作connection,如下:
SqlConnection connection = table1TableAdapter.Connection; 
table2TableAdapter.Connection 
= connection;
// Start a local Transaction 
SqlTransaction transaction = connection.BeginTransaction(); 
table1TableAdapter.MyAdapter.InsertCommand.Transaction 
= transaction; 
table2TableAdapter.MyAdapter.InsertCommand.Transaction 
= transaction; 
try 

// Update Database 
table1TableAdapter.Update(dataSet1.Table1); 
table2TableAdapter.Update(dataSet1.Table2); 
// Commit Changes to database 
transaction.Commit(); 
}
//more code here
   方法三:利用System.Reflection命名空間下的PropertyInfo類的GetProperty方法取得table adapter的私有connection屬性,附加上transaction對象後,再通過PropertyInfoSetValue方法將改造後的connection屬性設置回table adapter實例:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using System.Data.Common;
namespace CDSafe.DBUtilities
{
    
/// <summary>
    
/// a helper class when u are using a dataset's data adapter.
    
/// it use the reflection to add the transaction into the data adpater's connection
    
/// </summary>
   public sealed  class DataAdapterHelper
    {
       
/// <summary>
       
/// begin the transaction
       
/// </summary>
       
/// <param name="tableAdapter">the first data adapter in the transaction</param>
       
/// <param name="isolationLevel">the isolation level of the transaction</param>
       
/// <returns> a transaction object, use to add another data adapter into the same transaction</returns>
       public static DbTransaction BeginTransaction(object tableAdapter,IsolationLevel isolationLevel)
       {
           Type adapterType 
= tableAdapter.GetType();
           DbConnection connection 
= GetAdpaterConnection(tableAdapter);
           
if (connection.State == ConnectionState.Closed)
           {
               connection.Open();
           }
           DbTransaction transaction 
= connection.BeginTransaction(isolationLevel);
           SetTransaction(tableAdapter, transaction);
           
return transaction;
       }

       
/// <summary>
       
///  begin the transaction
       
/// </summary>
       
/// <param name="tableAdapter">the first data adapter in the transaction</param>
       
/// <returns>a transaction object, use to add another data adapter into the same transaction</returns>
       public static DbTransaction BeginTransaction(object tableAdapter)
       {
           
return BeginTransaction(tableAdapter, IsolationLevel.ReadCommitted);
       }

       
/// <summary>
       
/// use the reflection to get the table adapter's connection object
       
/// </summary>
       
/// <param name="tableAdapter"></param>
       
/// <returns>the connection object</returns>
       private static DbConnection GetAdpaterConnection(object tableAdapter)
       {
           Type adapterType 
= tableAdapter.GetType();
           PropertyInfo connectionProperty 
= adapterType.GetProperty("Connection",
               BindingFlags.NonPublic 
| BindingFlags.Instance);
           DbConnection connection 
= (DbConnection)connectionProperty.GetValue(tableAdapter, null);
           
return connection;
       }

       
/// <summary>
       
/// attach the connection which contains a transaction on the data adapter
       
/// </summary>
       
/// <param name="tableAdapter"></param>
       
/// <param name="connection"></param>
       private static void SetConnection(object tableAdapter, DbConnection connection)
       {
           Type type 
= tableAdapter.GetType();
           PropertyInfo connectionProperty 
= type.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance);
           connectionProperty.SetValue(tableAdapter, connection, 
null);
       }

       
/// <summary>
       
/// set transaction on the other data adapter
       
/// </summary>
       
/// <param name="tableAdapter"></param>
       
/// <param name="transaction"></param>
       public static void SetTransaction(object tableAdapter, DbTransaction transaction)
       {
           Type adapterType 
= tableAdapter.GetType();
           PropertyInfo commandsProperty 
= adapterType.GetProperty("CommandCollection"
               BindingFlags.NonPublic 
| BindingFlags.Instance);
           DbCommand[] commands 
= (DbCommand[])commandsProperty.GetValue(tableAdapter, null);
           
foreach (DbCommand command in commands)
           {
               command.Transaction 
= transaction;
           }
           PropertyInfo adpterProperty 
= adapterType.GetProperty("Adapter",
              BindingFlags.NonPublic 
| BindingFlags.Instance);
           DbDataAdapter dataAdapter 
= (DbDataAdapter)adpterProperty.GetValue(tableAdapter, null);
           
if (dataAdapter.InsertCommand != null)
           {
               dataAdapter.InsertCommand.Transaction 
= transaction;
           }
           
if (dataAdapter.DeleteCommand != null)
           {
               dataAdapter.DeleteCommand.Transaction 
= transaction;
           }
           
if (dataAdapter.UpdateCommand != null)
           {
               dataAdapter.UpdateCommand.Transaction 
= transaction;
           }
           
if (dataAdapter.SelectCommand != null)
           {
               dataAdapter.SelectCommand.Transaction 
= transaction;
           }
           SetConnection(tableAdapter, transaction.Connection);
       }
    }
}
DataAdater的command分兩種,一種是Adapter成員變量的insert,update,delete,還有一種是使用嚮導創建的command,這類command被放到了CommandCollection集合內。所以設置transaction時應考慮這兩種類型的command。
該helper class使用範例如下:
            TestTableAdapter adapter1 = new testTableAdapter();
            TableAdapter2 adapter2 
= new TableAdapter2();
            DbTransaction trans 
= DataAdapterHelper.BeginTransaction(adapter1);
            DataAdapterHelper.SetTransaction(adapter2, trans);
            adapter1.Insert(
"1""2");
            adapter2.Insert(
"3""4"null);
            trans.Commit();
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章