[C#] TableAdapter にトランザクション機能を実装するクラス

TableAdapterにトランザクションを実装
TableAdapterにトランザクションを実装

今は Visual C# 2005 Express Edition にて ADO.NET 2.0 Provider for SQLiteを利用してクライアントアプリの開発しています。

TableAdapterにてINSERTやupdateするとどうも更新が遅いので、Googleで調べたら

> http://journal.mycom.co.jp/special/2004/php5/007.html
> SQLiteでは明示的にトランザクションを開始しない限り、INSERT処理の前後に必ず”BEGIN”、”COMMIT”が実行される。

とのことでした。

で、色々試行錯誤して下記のVB記事を参考にC#&SQLite用のトランザクションの処理を追加。

TableAdapterにトランザクションを実装 / うなまな Blog
http://www.ailight.jp/blog/unaap/archive/2007/02/13/13566.aspx

ソースは次のとおりです。

とりあえず貼り付けて起きます、何か問題あったら連絡ください。

TableAdapterにトランザクション機能を実装するクラス
TableAdapterTransactor.cs

using System;
using System.Collections.Generic;
using System.Text;

using System.Data;
using System.Data.SQLite;
using System.Reflection;

/// 
/// TableAdapterにトランザクション機能を実装するクラス
/// 
/// 
/// 利用方法の例
///     TableAdapterTransactor tat = new TableAdapterTransactor();
///     Data1TableAdapter taData1 = new Data1TableAdapter();
///     Data2TableAdapter taData2 = new Data2TableAdapter();
///
///     tat.AddTableAdapter(taData1);
///     tat.AddTableAdapter(taData2);
///     tat.BeginTransaction();
///     try {
///         taData1.Insert...();
///         taData2.Insert...();
///         tat.Commit();
///     }
///     catch (Exception ex) {
///         tat.Rollback();
///     }
///
/// http://www.ailight.jp/blog/unaap/archive/2007/02/13/13566.aspx
/// 
class TableAdapterTransactor
{
	private SQLiteConnection _conn = null;
	private SQLiteTransaction _trans = null;
	private List

	_tableAdapters = new List();    #region "Pプロシージャ - GetConnection                     [TableAdapterのConnectionを取得する]"

	/// 
	/// TableAdapterのConnectionを取得する
	/// 
	///

	TableAdapter     /// 取得したConnection
	/// 
	private SQLiteConnection GetConnection(object tableAdapter)
	{
		Type type = tableAdapter.GetType();
		PropertyInfo connectionProperty = type.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance);
		SQLiteConnection connection = (SQLiteConnection)connectionProperty.GetValue(tableAdapter, null);
		return connection;
	}
	#endregion    #region "Pプロシージャ - SetConnection                     [TableAdapterのConnectionを設定する]"

	/// 
	/// TableAdapterのConnectionを設定する
	/// 
	///

	TableAdapter     /// Connection     /// 
	private void SetConnection(object tableAdapter, SQLiteConnection connection)
	{
		Type type = tableAdapter.GetType();
		PropertyInfo connectionProperty = type.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance);
		connectionProperty.SetValue(tableAdapter, connection, null);
	}
	#endregion    #region "Pプロシージャ - GetAdapter                        [TableAdapterのDataAdapterを取得する]"

	/// 
	/// TableAdapterのDataAdapterを取得する
	/// 
	///

	TableAdapter     /// 取得したDataAdapter
	/// 
	private SQLiteDataAdapter GetAdapter(object tableAdapter)
	{
		Type type = tableAdapter.GetType();
		FieldInfo adapterField = type.GetField("_adapter", BindingFlags.NonPublic | BindingFlags.Instance);
		SQLiteDataAdapter adapter = (SQLiteDataAdapter)adapterField.GetValue(tableAdapter);
		return adapter;
	}
	#endregion

	#region "Pプロシージャ - SetAdapter                        [TableAdapterのDataAdapterを設定する]"
	/// 
	/// TableAdapterのDataAdapterを設定する
	/// 
	/// TableAdapter     /// DataAdapter     /// 
	private void SetAdapter(object tableAdapter, SQLiteDataAdapter adapter)
	{
		Type type = tableAdapter.GetType();
		FieldInfo adapterField = type.GetField("_adapter", BindingFlags.NonPublic | BindingFlags.Instance);
		adapterField.SetValue(tableAdapter, adapter);
	}
	#endregion

	#region "Pプロシージャ - InitAdapter                       [TableAdapterのInitAdapterメソッドを呼び出す]"
	/// 
	/// TableAdapterのInitAdapterメソッドを呼び出す
	/// 
	/// TableAdapter     /// 利用しない
	private void InitAdapter(object tableAdapter)
	{
		Type type = tableAdapter.GetType();
		MethodInfo mi = type.GetMethod("InitAdapter", BindingFlags.NonPublic | BindingFlags.Instance);
		mi.Invoke(tableAdapter, null);
	}
	#endregion

	#region "Pプロシージャ - InitCommandCollection             [TableAdapterのInitCommandCollectionメソッドを呼び出す]"
	/// 
	/// TableAdapterのInitCommandCollectionメソッドを呼び出す
	/// 
	/// TableAdapter     /// 利用しない
	private void InitCommandCollection(object tableAdapter)
	{
		Type type = tableAdapter.GetType();
		MethodInfo mi = type.GetMethod("InitCommandCollection", BindingFlags.NonPublic | BindingFlags.Instance);
		mi.Invoke(tableAdapter, null);
	}
	#endregion

	#region "Pプロシージャ - SetTransactionCommands            [TableAdapterのCommandCollectionのTransactionを設定する]"
	/// 
	/// TableAdapterのCommandCollectionのTransactionを設定する
	/// 
	/// TableAdapter     /// Transaction     /// 
	private void SetTransactionCommands(object tableAdapter, SQLiteTransaction transaction)
	{
		Type type = tableAdapter.GetType();
		PropertyInfo commandsProperty = type.GetProperty("CommandCollection", BindingFlags.NonPublic | BindingFlags.Instance);
		SQLiteCommand[] commands = (SQLiteCommand[])commandsProperty.GetValue(tableAdapter, null);
		foreach (SQLiteCommand command in commands)
		{
			command.Transaction = transaction;
		}
		this.SetConnection(tableAdapter, transaction.Connection);
	}
	#endregion

	#region "Pプロシージャ - SetTransactionAdapter             [TableAdapterのDataAdapterのTransactionを設定する]"
	/// 
	/// TableAdapterのDataAdapterのTransactionを設定する
	/// 
	/// TableAdapter     /// Transaction     /// 
	private void SetTransactionAdapter(object tableAdapter, SQLiteTransaction transaction)
	{
		SQLiteDataAdapter adp = this.GetAdapter(tableAdapter);
		if (adp.InsertCommand != null)
		{
			adp.InsertCommand.Transaction = transaction;
		}
		if (adp.DeleteCommand != null)
		{
			adp.DeleteCommand.Transaction = transaction;
		}
		if (adp.UpdateCommand != null)
		{
			adp.UpdateCommand.Transaction = transaction;
		}
		this.SetAdapter(tableAdapter, adp);
		//this.InitCommandCollection(tableAdapter)
	}
	#endregion

	#region "メソッド - AddTableAdapter                        [TableAdapterを追加する]"
	/// 
	/// TableAdapterを追加する
	/// 
	/// TableAdapter     /// 
	public void AddTableAdapter(object tableAdapter)
	{
		this._tableAdapters.Add(tableAdapter);
	}
	#endregion

	#region "メソッド - BeginTransaction                       [トランザクションを開始する]"
	/// 
	/// トランザクションを開始する
	/// 
	/// 開始する前に、AddTableAdapterメソッドで対象となるTableAdapterを追加すること
	public void BeginTransaction()
	{
		int counter = 0;
		foreach (object adapter in this._tableAdapters)
		{
			counter += 1;
			if (counter == 1)
			{
				this._conn = this.GetConnection(adapter);
				if (this._conn.State != ConnectionState.Open)
				{
					this._conn.Open();
				}
				this._trans = this._conn.BeginTransaction();
			}
			this.SetConnection(adapter, this._conn);
			this.SetTransactionAdapter(adapter, this._trans);
			this.SetTransactionCommands(adapter, this._trans);
		}
	}

	/// 
	/// トランザクションを開始する
	/// 
	/// コネクション     /// 
	public void BeginTransaction(SQLiteConnection conn)
	{
		this._conn = conn;
		if (this._conn.State != ConnectionState.Open)
		{
			this._conn.Open();
		}
		this._trans = this._conn.BeginTransaction();
		foreach (object adapter in this._tableAdapters)
		{
			this.SetConnection(adapter, this._conn);
			this.SetTransactionAdapter(adapter, this._trans);
			this.SetTransactionCommands(adapter, this._trans);
		}
	}

	/// 
	/// トランザクションを開始する
	/// 
	/// トランザクション     /// 
	public void BeginTransaction(SQLiteTransaction trans)
	{
		this._conn = trans.Connection;
		this._trans = trans;
		foreach (object adapter in this._tableAdapters)
		{
			this.SetConnection(adapter, this._conn);
			this.SetTransactionAdapter(adapter, this._trans);
			this.SetTransactionCommands(adapter, this._trans);
		}
	}
	#endregion

	#region "メソッド - Commit                                 [トランザクションをコミットする]"
	/// 
	/// トランザクションをコミットする
	/// 
	/// 
	public void Commit()
	{
		try
		{
			this._trans.Commit();
		}
		catch (Exception ex)
		{
			this._trans.Rollback();
			throw ex;
		}
		finally
		{
			if ((this._conn.State == ConnectionState.Open))
			{
				this._conn.Close();
			}
		}
	}
	#endregion

	#region "メソッド - Rollback                               [トランザクションをロールバックする]"
	/// 
	/// トランザクションをロールバックする
	/// 
	/// 
	public void Rollback()
	{
		this._trans.Rollback();
		if ((this._conn.State == ConnectionState.Open))
			{
				this._conn.Close();
			}
		}
		#endregion
	}
}
//eof


はずかしながら↓
ttp://bbs.wankuma.com/index.cgi?mode=al2&namber=4858


※ 2008/12/5 ソースコードのインデントが崩れていたので修正しました。

コメント

  1. atc より:

    [C#] TableAdapter にトランザクション機能を実装するクラス : [ま]技術雑記 http://htn.to/moBBkY