工作单元模式(UnitOfWork)学习总结
工作单元的目标是维护变化的对象列表。使用IUnitOfWorkRepository负责对象的持久化,使用IUnitOfWork收集变化的对象,并将变化的对象放到各自的增删改列表中,
最后Commit,Commit时需要循环遍历这些列表,并由Repository来持久化。
要实现一个银行卡简单转账的功能,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=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();
}
}
}

浙公网安备 33010602011771号