UnitOfWork机制的实现和注意事项
UnitOfWork机制
/*一点牢骚:
* UnitOfWork机制的蛋疼之处:
* UnitOfWork机制,决定了插入新的实体前,要预先设置数据库中的主键Id,尽管数据库自己生产主键。
* 但是,如果自己能生成主键还要数据库自动生成主键干什么,即使自己生成主键不能保证主键的唯一性,
* 除非主键是GUID。
*
* if (!addedEntities.ContainsKey(entity))
{
addedEntities.Add(entity, unitofWorkRepository);
};
* 判断实体的唯一性标准是调用实体的GetHashCode();
* public override int GetHashCode()
{
return this.Id.GetHashCode();
}
*而 this.Id是实体在数据库的主键(一般用数据库自动生成),但我插入前怎么能由我生成能。
*如果人工生成不能保证主键的唯一性,就不能添加到所以addedEntities中,也就不能保存到数据库。
*折中的解决方案是每添加一个新的实体,就Commit一次(马上提交到数据库,并清空addedEntities)。
*
*/
---------------------------------------------------------冷静分割线---------------------------------------------------
仓储实现UintOfWork机制
1.目标:
实现仓储实现UintOfWork机制(UintOfWork机制的目的是实现实体的持久化操作的原子性,保证数据的一致性)
2.具体的实现思路:
图解:
伪代码:
(1)仓储类Repository的定义
Repository类 { 虚拟增(实体entity) { UintOfWork对象.增登记(实体entity,this) }; 虚拟删(实体entity) { UintOfWork对象.删登记(实体entity,this) }; 虚拟改Add(实体entity) { UintOfWork对象. 改登记(实体entity,this) }; 真的增到数据库(实体entity) { AddTo数据库(实体entity) }; 真的删到数据库(实体entity) { RemovFrom数据库(实体entity) }; 真的改保存到数据库(实体entity) { UpdateTo数据库(实体entity) }; }
(2)UnitOfWork类的定义:
UnitOfWork { 被增实体的字典 = new (); 被删实体的字典 = new (); 被改实体的字典 = new(); 增登记(实体entity,Repository) {
if(如果被增实体的字典包不含实体entity) 被增实体的字典.Add(实体entity,Repository); } 删登记(实体entity,Repository) {
if (如果被删实体的字典不包含实体enity) 被删实体的字典.Add(实体entity,Repository); } 改登记(实体entity,Repository) {
if(如果被改实体的字典不包含实体entity) 被改实体的字典.Add(实体entity,Repository); } 统一提交到数据库Commit() { for(int i = 0 ; i < 被增实体的字典.lengh; ++i ) { 实体entity tmpEntity = 被增实体的字典[i].Key; Repository repository = 被增实体的字典[i].Value; repository.真的增保存到数据库(tmpEntity); } for(int i = 0 ; i < 被删实体的字典.lengh; ++i ) { 实体entity tmpEntity = 被删实体的字典[i].Key; Repository repository = 被删实体的字典[i].Value; repository.真的删保存到数据库(tmpEntity); } for(int i = 0 ; i < 被改实体的字典.lengh; ++i ) { 实体entity tmpEntity = 被改实体的字典[i].Key; Repository repository = 被改实体的字典[i].Value; repository.真的改保存到数据库(tmpEntity); } } }
3.光说不练,代码实现:
IUnitOfWorkRepository.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using NCS.Infrastructure.Domain; 6 7 namespace NCS.Infrastructure.UnitOfWork 8 { 9 /// <summary> 10 /// Repository实现了UnitOfWork机制的Repository 11 /// </summary> 12 public interface IUnitOfWorkRepository 13 { 14 /// <summary> 15 /// 实体的持久化操作(包括三个操作:增Add、删remove、改save,注意不包括查询)前, 16 /// 先用UnitOfWork进行登记, 17 /// 以便日后由UnitOfWork统一(原子性)通过Commit操作,提交修改到数据库(持久化操作) 18 /// </summary> 19 IUnitOfWork UnitOfWork { get; set; } 20 21 /** 22 * Persist持久化系列函数 23 */ 24 void PersistCreationOf(IAggregateRoot entity); 25 void PersistUpdateOf(IAggregateRoot entity); 26 void PersistDeletionOf(IAggregateRoot entity); 27 } 28 }
IUnitOfWork.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NCS.Infrastructure.Domain; namespace NCS.Infrastructure.UnitOfWork { /// <summary> /// UnitOfWork模式: /// 1.跟踪领域实体聚合的变化 /// 2.原子操作中完成实体聚合的持久化 /// 3.具体实现: /// 实体的进行持久化操作(包括三个操作:增Add、删remove、改save,注意不包括查询)前, /// 先用UnitOfWork进行登记, /// 以便日后由UnitOfWork统一(原子性)通过Commit操作,提交修改到数据库(持久化操作) /// </summary> /// </summary> public interface IUnitOfWork { /// <summary> /// 注册登记被添加的实体 /// </summary> /// <param name="entity">目标实体</param> /// <param name="unitofWorkRepository">实体所在的仓储</param> void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository); /// <summary> /// 注册登记被删除的实体 /// </summary> /// <param name="entity">目标实体</param> /// <param name="unitofWorkRepository">实体所在的仓储</param> void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository); /// <summary> /// 注册登记被修改的实体 /// </summary> /// <param name="entity">目标实体</param> /// <param name="unitofWorkRepository">实体所在的仓储</param> void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository); void Commit(); } }
AdoUnitOfWork.cs
1 /*一点牢骚: 2 * UnitOfWork机制的蛋疼之处: 3 * UnitOfWork机制,决定了插入新的实体前,要预先设置数据库中的主键Id,尽管数据库自己生产主键。 4 * 但是,如果自己能生成主键还要数据库自动生成主键干什么,即使自己生成主键不能保证主键的唯一性, 5 * 除非主键是GUID。 6 * 7 * if (!addedEntities.ContainsKey(entity)) 8 { 9 addedEntities.Add(entity, unitofWorkRepository); 10 }; 11 * 判断实体的唯一性标准是调用实体的GetHashCode(); 12 * public override int GetHashCode() 13 { 14 return this.Id.GetHashCode(); 15 } 16 *而 this.Id是实体在数据库的主键(一般用数据库自动生成),但我插入前怎么能由我生成呢!!! 17 *因为: 18 *1.不知主键的数据库类型; 19 *2.即使知道主键的数据库类型,也不能因为硬编码造成的依赖,耦合。 20 *3.人工生成不能保证主键的唯一性, 21 *综上,所以就不能添加到addedEntities中,也就不能保存到数据库。 22 *折中的解决方案是每添加一个新的实体,就Commit一次(马上提交到数据库,并清空addedEntities)。 23 * 24 */ 25 26 using System; 27 using System.Collections.Generic; 28 using System.Linq; 29 using System.Text; 30 using NCS.Infrastructure.Domain; 31 using NCS.Infrastructure.UnitOfWork; 32 using System.Transactions; 33 34 namespace NCS.Repository.ADO 35 { 36 public class AdoUnitOfWork : IUnitOfWork 37 { 38 private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities; 39 private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities; 40 private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities; 41 42 public AdoUnitOfWork() 43 { 44 addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>(); 45 changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>(); 46 deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>(); 47 } 48 49 #region IUnitOfWork member 50 51 #region 注册登记实体 52 public void RegisterNew(IAggregateRoot entity, 53 IUnitOfWorkRepository unitofWorkRepository) 54 { 55 if (!addedEntities.ContainsKey(entity)) 56 { 57 addedEntities.Add(entity, unitofWorkRepository); 58 }; 59 } 60 61 public void RegisterRemoved(IAggregateRoot entity, 62 IUnitOfWorkRepository unitofWorkRepository) 63 { 64 if (!deletedEntities.ContainsKey(entity)) 65 { 66 deletedEntities.Add(entity, unitofWorkRepository); 67 } 68 } 69 70 public void RegisterAmended(IAggregateRoot entity, 71 IUnitOfWorkRepository unitofWorkRepository) 72 { 73 if (!changedEntities.ContainsKey(entity)) 74 { 75 changedEntities.Add(entity, unitofWorkRepository); 76 } 77 } 78 79 #endregion 80 public void Commit() 81 { 82 using (TransactionScope scope = new TransactionScope()) 83 { 84 foreach (IAggregateRoot entity in this.addedEntities.Keys) 85 { 86 this.addedEntities[entity].PersistCreationOf(entity); 87 } 88 89 foreach (IAggregateRoot entity in this.changedEntities.Keys) 90 { 91 this.changedEntities[entity].PersistUpdateOf(entity); 92 } 93 94 foreach (IAggregateRoot entity in this.deletedEntities.Keys) 95 { 96 this.deletedEntities[entity].PersistDeletionOf(entity); 97 } 98 99 scope.Complete(); 100 101 this.addedEntities.Clear(); 102 this.changedEntities.Clear(); 103 this.deletedEntities.Clear(); 104 } 105 } 106 107 #endregion 108 109 } 110 }
Repository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NCS.Infrastructure.Domain; using NCS.Infrastructure.Querying; using NCS.Infrastructure.UnitOfWork; using NCS.Repository.ADO.DataSession; namespace NCS.Repository.ADO.Repositories { public abstract class Repository<T, TEntityKey> : IUnitOfWorkRepository where T : IAggregateRoot { private IUnitOfWork unitOfWork; private IDataSession<T, TEntityKey> dataSession; public Repository(IUnitOfWork unitOfWork) { this.UnitOfWork = unitOfWork; DataSession = DataSessionFactory.GetDataSession<T, TEntityKey>(); } public IUnitOfWork UnitOfWork { get { return unitOfWork; } set { unitOfWork = value; } } public IDataSession<T, TEntityKey> DataSession { get { return dataSession; } set { dataSession = value; } } #region 持久化 public void Add(T entity) { UnitOfWork.RegisterNew(entity, this); } public void Remove(T entity) { UnitOfWork.RegisterNew(entity, this); } public void Remove(Query query) { //TODO:好像Remove(Query query)并不能保证事务操作,因为没添加到UnitOfWork里面 //先提交事务 unitOfWork.Commit(); DataSession = DataSessionFactory.GetDataSession<T, TEntityKey>(); DataSession.Remove(query); } public void Save(T entity) { UnitOfWork.RegisterRemoved(entity, this); } #endregion #region 查询部分 public T FindBy(TEntityKey id) { return this.DataSession.FindBy(id); } public IEnumerable<T> FindAll() { return this.DataSession.FindAll(); } public IEnumerable<T> FindAll(int index, int count) { return this.DataSession.FindAll().Skip(index).Take(count); } public IEnumerable<T> FindBy(Query query) { return this.DataSession.FindBy(query); } public IEnumerable<T> FindBy(Query query, int index, int count) { return this.DataSession.FindBy(query, index, count); } #endregion #region IUnitOfWorkRepository members public virtual void PersistCreationOf(IAggregateRoot entity) { this.DataSession.Add((T)entity); } public virtual void PersistUpdateOf(IAggregateRoot entity) { this.DataSession.Save((T)entity); } public virtual void PersistDeletionOf(IAggregateRoot entity) { this.DataSession.Remove((T)entity); } #endregion } }