Transactions in the Repository Pattern

后端 未结 6 869
小鲜肉
小鲜肉 2020-12-12 18:07

How do I encapsulate the saving of more than one entity in a transactional manner using the repository pattern? For example, what if I wanted to add an order and update the

6条回答
  •  隐瞒了意图╮
    2020-12-12 18:38

    Booting my computer this morning I faced the exact problem for a project I am working on. I had some ideas which lead to the following design - and comments would be more than awesome. Unfortunately the design suggested by Josh isn't possible, as I have to work with a remote SQL server and can't enable the Distribute Transaction Coordinator service it relies on.

    My solution is based on a few yet simple changes to my existing code.

    First, I have all my repositories implement a simple marker interface:

    /// 
    /// A base interface for all repositories to implement.
    /// 
    public interface IRepository
    { }
    

    Secondly, I let all my transaction enabled repositories implement the following interface:

    /// 
    /// Provides methods to enable transaction support.
    /// 
    public interface IHasTransactions : IRepository
    {
        /// 
        /// Initiates a transaction scope.
        /// 
        void BeginTransaction();
    
        /// 
        /// Executes the transaction.
        /// 
        void CommitTransaction();
    }
    

    The idea is that in all my repositories I implement this interface and add code which introduces transaction directly depending on the actual provider (for fake repositories I have made a list of delegates which gets executed on commit). For LINQ to SQL it would be easy to make implementations such as:

    #region IHasTransactions Members
    
    public void BeginTransaction()
    {
        _db.Transaction = _db.Connection.BeginTransaction();
    }
    
    public void CommitTransaction()
    {
        _db.Transaction.Commit();
    }
    
    #endregion
    

    This of course requires that a new repository class is created for each thread, but this is reasonable for my project.

    Each method using the repository needs to invoke the BeginTransaction() and the EndTransaction(), if the repository implements IHasTransactions. To make this call even easier, I came up with the following extensions:

    /// 
    /// Extensions for spawning and subsequently executing a transaction.
    /// 
    public static class TransactionExtensions
    {
        /// 
        /// Begins a transaction if the repository implements .
        /// 
        /// 
        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();
            }
        }
    }
    

    Comments are appreciated!

提交回复
热议问题