0%

      工作单元的目标是维护变化的对象列表。使用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
{

}

}

View Code

     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();
}
}

View Code

    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);
}
}

View Code

    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 }

}

View Code

    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);
}
}

View Code

    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=T57649\MSSQLSERVER2012;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();
    }
}

}

View Code