Thinking In Design Pattern——Unit Of Work(工作單元)模式探索


什么是Unit Of Work模式

Unit Of Work(工作單元)模式用來維護一個由已經被業務事物修改(增加、刪除或更新)的業務對象組成的列表。Unit  Of Work模式負責協調這些修改的持久化工作以及所有標記的並發問題。在數據訪問層中采用Unit Of Work模式帶來的好處是能夠確保數據完整性。如果在持久化一系列業務對象(他們屬於同一個事物)的過程中出現問題,那么應該將所有的修改回滾,以確保數據始終處於有效狀態。

為了演示Unit Of Work模式,使用一個簡單的銀行領域對兩個賬號之間的轉賬建模。下圖給出了服務層(AccountService)與使用了Unit Of Work模式(以確保轉賬作為原子事物的Unit Of Work提交)的資源層(AccountRepository)之間的交互。

 

記住這張圖,因為下面的代碼邏輯都是依照這張圖的定義來實現的。

建立Infrastructure

  • 下面開始編寫解決方案的代碼,首先創建Unit Of Work模式的所有配套的基礎設施代碼
 public interface IAggregateRoot
    {
    }

IAggregateRoot接口實際上屬於標記接口,這個接口充當了類和方法的元數據,我們構建的資源庫只持久化實現了IAggregateRoot接口的業務對象,所以Unit Of Work的實現將使用IAggregateRoot接口來引用原子事物中涉及的任何業務實體

  • 添加另外一個接口IUnitOfWorkRepository,這是一個用來持久化操作的接口:
 public interface IUnitOfWorkRepository
    {
        void PersistCreationOf(IAggregateRoot entity);
        void PersistUpdateOf(IAggregateRoot entity);
        void PersistDeletionOf(IAggregateRoot entity);
    }
  • 之后,向Infrastructure項目中添加IUnitOfWork接口:
 public interface IUnitOfWork
    {
        void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void Commit();
    }

 值得注意的是IUnitOfWork接口在注冊修改/增加/刪除時需要IUnitOfWorkRepository,這樣在提交時,Unit Of Work可以將真正持久化的工作委托給適當的具體實現。

  • 最后向Infrastructure項目中添加UnitOfWork,實現IUnitOfWork:
 public class UnitOfWork : IUnitOfWork 
    {
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;

        public UnitOfWork()
        {
            addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
            changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
            deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
        }

        public void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!changedEntities.ContainsKey(entity))
            {
                changedEntities.Add(entity, unitofWorkRepository);
            }
        }

        public void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!addedEntities.ContainsKey(entity))
            {
                addedEntities.Add(entity, unitofWorkRepository);
            };
        }

        public void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!deletedEntities.ContainsKey(entity))
            {
                deletedEntities.Add(entity, unitofWorkRepository);
            }
        }
        
        public void Commit()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                foreach (IAggregateRoot entity in this.addedEntities.Keys)
                {
                    this.addedEntities[entity].PersistCreationOf(entity);
                }

                foreach (IAggregateRoot entity in this.changedEntities.Keys)
                {
                    this.changedEntities[entity].PersistUpdateOf(entity);
                }

                foreach (IAggregateRoot entity in this.deletedEntities.Keys)
                {
                    this.deletedEntities[entity].PersistDeletionOf(entity);
                }

                scope.Complete(); 
            }
        }

    }

UnitOfWork類使用3個字典變量來跟蹤對業務實體的代執行修改。第一個字典對應於被添加到數據存儲的實體,第2個字典跟蹤帶更新的實體,而第三個字典處理實體刪除,與字典中的實體鍵匹配的IUnitOfWorkRepository將被保存下來,並用於Commit方法之中,來調用Repository對象,該對象包含真正持久化實體的代碼。Commit方法遍歷每一個字典,並調用相應的IUnitOfWorkRepository方法(傳遞實體引用)。Commit方法中的工作均被TransactionScope代碼包裝起來,如果在IUnitOfWorkRepository中執行任務時出現異常,則所有工作回滾,數據存儲將保持原來的狀態。

建立Model

  • 向Model中添加一個新類Account,表示銀行賬戶,為了方便演示簡單處理了:
public class Account : IAggregateRoot 
    {
        public decimal balance { get; set; }
    }
  •   為了將Accout持久化,添加IAccountRepository接口:
public interface IAccountRepository
    {
        void Save(Account account);
        void Add(Account account);
        void Remove(Account account);                
    }
  • 添加AccountService服務類來協調兩個賬戶之間的轉賬工作。
public class AccountService
    {
        private IAccountRepository _accountRepository;
        private IUnitOfWork _unitOfWork;
        /// <summary>
        /// AccountService通過其構造器實現依賴注入
        /// </summary>
        /// <param name="accountRepository"></param>
        /// <param name="unitOfWork"></param>
        public AccountService(IAccountRepository accountRepository,
                              IUnitOfWork unitOfWork)
        {
            _accountRepository = accountRepository;
            _unitOfWork = unitOfWork;            
        }
        /// <summary>
        /// 實現兩個賬戶之間轉賬工作
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="amount"></param>
        public void Transfer(Account from, Account to, decimal amount)
        {
            if (from.balance >= amount)
            {
                from.balance -= amount;
                to.balance += amount;

                _accountRepository.Save(from);
                _accountRepository.Save(to);
                _unitOfWork.Commit();
            }
        }
    }

接着,它調用賬戶Repository來保存兩個賬戶,最后,它調用Unit Of Work實例的Commit方法來確保該交易作為原子的Unit Of Work完成。所以接下來的重點就是怎樣Repository與Unit Of Work交互。

建立Repository來持久化業務實體

 public class AccountRepository : IAccountRepository, IUnitOfWorkRepository 
    {
        private IUnitOfWork _unitOfWork;

        public AccountRepository(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        public void Save(Account account)
        {            
            _unitOfWork.RegisterAmended(account, this);            
        }

        public void Add(Account account)
        {
            _unitOfWork.RegisterNew(account, this);
        }

        public void Remove(Account account)
        {
            _unitOfWork.RegisterRemoved(account, this);
        }  

        public void PersistUpdateOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH來持久化
        }

        public void PersistCreationOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH來持久化
        }

        public void PersistDeletionOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH來持久化
        }              
    }

OK,這樣Unit Of Work工作模式就搭建好了,AccountRepository實現了IAccountRepositoryIUnitOfWorkRepository接口,IAccountRepository方法的實現簡單地將工作委托給Unit Of Work(傳入待持久化的實體以及Repository的引用),最后,調用Unit Of Work類的Commit方法,其實是Unit Of Work引用Repository的IUnitOfWorkRepository的接口契約來真正完成持久化任務,至於持久化操作你可以用Ado.net或者EF、NH等。

回過頭來再看這幅圖,原來Unit Of Work也就是如此罷了:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM