工作单元模式(UnitOfWork)学习总结

工作单元的目标是维护变化的对象列表。使用IUnitOfWorkRepository负责对象的持久化,使用IUnitOfWork收集变化的对象,并将变化的对象放到各自的增删改列表中,

最后Commit,Commit时需要循环遍历这些列表,并由Repository来持久化。

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

      要实现一个银行卡简单转账的功能,Demo框架如下设计:

      

      代码实现如下:

     

      EntityBase,领域类的基类。

     

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jack.Gao.UnitOfWork.Infrastructure
{
    public class EntityBase
    {

    }
}
复制代码

     IUnitOfWork,复杂维护变化的对象列表,并最后Commit,依次遍历变化的列表,并持久化,这就是Commit的事情。

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jack.Gao.UnitOfWork.Infrastructure
{
    public interface IUnitOfWork
    {
        void RegisterAdded(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository);
        void RegisterChangeded(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository);
        void RegisterRemoved(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository);
        void Commit();
    }
}
复制代码

    

    IUnitOfWorkRepository,负责持久化对象。

   

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jack.Gao.UnitOfWork.Infrastructure
{
    public interface IUnitOfWorkRepository
    {
        void PersistNewItem(EntityBase entityBase);
        void PersistUpdatedItem(EntityBase entityBase);
        void PersistDeletedItem(EntityBase entityBase);
    }
}
复制代码

   

    UnitOfWork,IUnitOfWork的具体实现。

   

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Transactions;
 7 
 8 namespace Jack.Gao.UnitOfWork.Infrastructure
 9 {
10     public class UnitOfWork:IUnitOfWork
11     {
12         #region Fields
13 
14         private Dictionary<EntityBase, IUnitOfWorkRepository> addedEntities;
15         private Dictionary<EntityBase, IUnitOfWorkRepository> changededEntities;
16         private Dictionary<EntityBase, IUnitOfWorkRepository> removedEntities;
17 
18         #endregion
19 
20         #region Constructor
21 
22         public UnitOfWork()
23         {
24             addedEntities=new Dictionary<EntityBase, IUnitOfWorkRepository>();
25             changededEntities=new Dictionary<EntityBase, IUnitOfWorkRepository>();
26             removedEntities=new Dictionary<EntityBase, IUnitOfWorkRepository>();
27         }
28 
29         #endregion
30 
31         #region Implement IUnitOfWork
32 
33         public void RegisterAdded(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository)
34         {
35             this.addedEntities.Add(entityBase,unitOfWorkRepository);
36         }
37 
38         public void RegisterChangeded(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository)
39         {
40             this.changededEntities.Add(entityBase,unitOfWorkRepository);
41         }
42 
43         public void RegisterRemoved(EntityBase entityBase, IUnitOfWorkRepository unitOfWorkRepository)
44         {
45             this.removedEntities.Add(entityBase,unitOfWorkRepository);
46         }
47 
48         public void Commit()
49         {
50             using (TransactionScope transactionScope=new TransactionScope())
51             {
52                 foreach (var entity in addedEntities.Keys)
53                 {
54                     addedEntities[entity].PersistNewItem(entity);
55                 }
56 
57                 foreach (var entity in changededEntities.Keys)
58                 {
59                     changededEntities[entity].PersistUpdatedItem(entity);
60                 }
61 
62                 foreach (var entity in removedEntities.Keys)
63                 {
64                     removedEntities[entity].PersistDeletedItem(entity);
65                 }
66 
67                 transactionScope.Complete();
68             }
69         }
70 
71         #endregion
72     }
73 }
复制代码


   

    BankAccount,继承自领域基类EntityBase。

   

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Jack.Gao.UnitOfWork.Infrastructure;

namespace Jack.gao.UnitOfWork.Domain
{
    public class BankAccount:EntityBase
    {
        #region Field

        public int Id { get; set; }

        public decimal Balance { get; set; }

        #endregion

        #region operator +

        public static BankAccount operator+(BankAccount accountLeft,BankAccount accountRight)
        {
            BankAccount account = new BankAccount();

            account.Balance = accountLeft.Balance + accountRight.Balance;

            return account;
        }

        #endregion
    }
}
复制代码

  

    IAccountRepository,持久化BankAcount接口

  

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jack.gao.UnitOfWork.Domain
{
    public interface IAccountRepository
    {
        void Save(BankAccount account);
        void Add(BankAccount account);
        void Remove(BankAccount account);
    }
}
复制代码

   

    BankAccountService,服务类,实现转账服务。

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using Jack.Gao.UnitOfWork.Infrastructure;
 7 
 8 namespace Jack.gao.UnitOfWork.Domain
 9 {
10     public class BankAccountService
11     {
12         #region Field
13 
14         private IAccountRepository _accountRepository;
15         private IUnitOfWork _unitOfWork;
16 
17         #endregion
18 
19         #region Constructor
20 
21         public BankAccountService(IAccountRepository accountRepository, IUnitOfWork unitOfWork)
22         {
23             this._accountRepository = accountRepository;
24             this._unitOfWork = unitOfWork;
25         }
26 
27         #endregion
28 
29         #region Method
30 
31         public void TransferMoney(BankAccount from, BankAccount to, decimal balance)
32         {
33             if (from.Balance>=balance)
34             {
35                 from.Balance = from.Balance - balance;
36                 to.Balance = to.Balance + balance;
37 
38                 _accountRepository.Save(from);
39                 _accountRepository.Save(to);
40                 _unitOfWork.Commit();
41             }
42         }
43 
44         #endregion
45     }
46 }
复制代码


    AccountRepository,持久化具体实现,使用ADO.NET实现,也可以使用其他的EF,NHbernate

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 using Jack.gao.UnitOfWork.Domain;
  7 using Jack.Gao.UnitOfWork.Infrastructure;
  8 using System.Data.SqlClient;
  9 
 10 namespace Jack.gao.UnitOfWork.Persistence
 11 {
 12     public class AccountRepository:IAccountRepository,IUnitOfWorkRepository
 13     {
 14         #region Field
 15 
 16         private const string _connectionString = @"Data Source=T57649MSSQLSERVER2012;Initial Catalog=DB_Customer;Integrated Security=True";
 17 
 18         private IUnitOfWork _unitOfWork;
 19 
 20         #endregion
 21 
 22         #region Constructor
 23 
 24         public AccountRepository(IUnitOfWork unitOfWork)
 25         {
 26             this._unitOfWork = unitOfWork;
 27         }
 28 
 29         #endregion
 30 
 31         #region Implement interface IAccountRepository,IUnitOfWorkRepository
 32 
 33         public void Save(BankAccount account)
 34         {
 35             _unitOfWork.RegisterChangeded(account,this);
 36         }
 37 
 38         public void Add(BankAccount account)
 39         {
 40             _unitOfWork.RegisterAdded(account,this);
 41         }
 42 
 43         public void Remove(BankAccount account)
 44         {
 45             _unitOfWork.RegisterRemoved(account,this);
 46         }
 47 
 48         public void PersistNewItem(EntityBase entityBase)
 49         {
 50             BankAccount account = (BankAccount)entityBase;
 51 
 52             string insertAccountSql = string.Format("insert into DT_Account(balance,Id) values({0},{1})", account.Balance, account.Id);
 53 
 54             SqlConnection sqlConnection = new SqlConnection(_connectionString);
 55 
 56             try
 57             {
 58                 sqlConnection.Open();
 59 
 60                 SqlCommand sqlCommand = new SqlCommand(insertAccountSql, sqlConnection);
 61 
 62                 sqlCommand.ExecuteNonQuery();
 63             }
 64             catch (Exception ex)
 65             {
 66                 throw ex;
 67             }
 68             finally
 69             {
 70                 sqlConnection.Close();
 71             }
 72         }
 73 
 74         public void PersistUpdatedItem(EntityBase entityBase)
 75         {
 76             BankAccount account = (BankAccount)entityBase;
 77 
 78             string updateAccountSql = string.Format("update DT_Account set balance={0} where Id={1}", account.Balance,account.Id);
 79 
 80             SqlConnection sqlConnection = new SqlConnection(_connectionString);
 81 
 82             try
 83             {
 84                 sqlConnection.Open();
 85 
 86                 SqlCommand sqlCommand = new SqlCommand(updateAccountSql, sqlConnection);
 87 
 88                 sqlCommand.ExecuteNonQuery();
 89             }
 90             catch (Exception ex)
 91             {
 92                 throw ex;
 93             }
 94             finally
 95             {
 96                 sqlConnection.Close();
 97             }
 98         }
 99 
100         public void PersistDeletedItem(EntityBase entityBase)
101         {
102             BankAccount account = (BankAccount)entityBase;
103 
104             string deleteAccountSql = string.Format("delete from DT_Account where Id={0}", account.Id);
105 
106             SqlConnection sqlConnection = new SqlConnection(_connectionString);
107 
108             try
109             {
110                 sqlConnection.Open();
111 
112                 SqlCommand sqlCommand = new SqlCommand(deleteAccountSql, sqlConnection);
113 
114                 sqlCommand.ExecuteNonQuery();
115             }
116             catch (Exception ex)
117             {
118                 throw ex;
119             }
120             finally
121             {
122                 sqlConnection.Close();
123             }
124         }
125 
126         #endregion
127 
128         #region Method
129 
130         public BankAccount GetAccount(BankAccount account)
131         {
132             account.Balance = 100;
133             return account;
134         }
135 
136         #endregion
137     }
138 }
复制代码

    AccountRepositoryTest,测试AccountRepository中的方法

复制代码
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Jack.gao.UnitOfWork.Domain;
using Jack.Gao.UnitOfWork.Infrastructure;
using Jack.gao.UnitOfWork.Persistence;

namespace Jack.gao.UnitOfWork.Test
{
    [TestClass]
    public class AccountRepositoryTest
    {
        private IUnitOfWork unitOfWork;
        private IAccountRepository accountRepository;
        private BankAccountService accountService;

        public AccountRepositoryTest()
        {
            unitOfWork = new Jack.Gao.UnitOfWork.Infrastructure.UnitOfWork();
            accountRepository = new AccountRepository(unitOfWork);
            accountService = new BankAccountService(accountRepository, unitOfWork);
        }


        [TestMethod]
        public void Add()
        {
            var accountLeft = new BankAccount() { Balance = 200, Id = 1 };
            var accountRight = new BankAccount() { Balance = 10, Id = 2 };

            accountRepository.Add(accountLeft);
            accountRepository.Add(accountRight);

            unitOfWork.Commit();
        }

        [TestMethod]
        public void Save()
        {
            var accountLeft = new BankAccount() { Balance = 200, Id = 1 };
            var accountRight = new BankAccount() { Balance = 10, Id = 2 };


            accountService.TransferMoney(accountLeft, accountRight, 100);
        }

        [TestMethod]
        public void Remove()
        {
            var accountLeft = new BankAccount() { Balance = 200, Id = 1 };

            accountRepository.Remove(accountLeft);

            unitOfWork.Commit();
        }
    }
}
原文地址:https://www.cnblogs.com/bdbw2012/p/4755319.html