今朝コンピュータを起動すると、私が取り組んでいるプロジェクトの正確な問題に直面しました。次のデザインにつながるいくつかのアイデアがありました。残念ながら、Josh が提案した設計は不可能です。リモートの SQL サーバーで作業する必要があり、依存する Distribute Transaction Coordinator サービスを有効にできないからです。
私のソリューションは、既存のコードへのいくつかの単純な変更に基づいています。
まず、すべてのリポジトリに単純なマーカー インターフェースを実装します。
/// <summary>
/// A base interface for all repositories to implement.
/// </summary>
public interface IRepository
{ }
次に、すべてのトランザクション対応リポジトリに次のインターフェイスを実装させます。
/// <summary>
/// Provides methods to enable transaction support.
/// </summary>
public interface IHasTransactions : IRepository
{
/// <summary>
/// Initiates a transaction scope.
/// </summary>
void BeginTransaction();
/// <summary>
/// Executes the transaction.
/// </summary>
void CommitTransaction();
}
アイデアは、すべてのリポジトリでこのインターフェイスを実装し、実際のプロバイダーに応じてトランザクションを直接導入するコードを追加することです (偽のリポジトリの場合、コミット時に実行されるデリゲートのリストを作成しました)。LINQ to SQL の場合、次のような実装を簡単に作成できます。
#region IHasTransactions Members
public void BeginTransaction()
{
_db.Transaction = _db.Connection.BeginTransaction();
}
public void CommitTransaction()
{
_db.Transaction.Commit();
}
#endregion
もちろん、これにはスレッドごとに新しいリポジトリ クラスを作成する必要がありますが、これは私のプロジェクトでは妥当です。
リポジトリが を実装している場合、リポジトリを使用する各メソッドはBeginTransaction()
およびを呼び出す必要があります。この呼び出しをさらに簡単にするために、次の拡張機能を思い付きました。EndTransaction()
IHasTransactions
/// <summary>
/// Extensions for spawning and subsequently executing a transaction.
/// </summary>
public static class TransactionExtensions
{
/// <summary>
/// Begins a transaction if the repository implements <see cref="IHasTransactions"/>.
/// </summary>
/// <param name="repository"></param>
public static void BeginTransaction(this IRepository repository)
{
var transactionSupport = repository as IHasTransactions;
if (transactionSupport != null)
{
transactionSupport.BeginTransaction();
}
}
public static void CommitTransaction(this IRepository repository)
{
var transactionSupport = repository as IHasTransactions;
if (transactionSupport != null)
{
transactionSupport.CommitTransaction();
}
}
}
コメントは大歓迎です!