在一個方法中,它一般會做一件事情,這樣的方法在功能上比較清晰,在職責上也很單一(這里的單一是褒義的,呵呵),而它所做的這件事,從頭到尾會把它做完,不會做到一半的功能,這屬於功能上的不完整,這不是我們推薦的。
項目中的代碼:
完整的提交方法:
protected virtual void SaveChanges() { if (!iUnitWork.IsNotSubmit) iUnitWork.Save(); }
完整的插入方法:
public virtual void Add(TEntity item) { _db.Entry<TEntity>(item); _db.Set<TEntity>().Add(item); this.SaveChanges(); }
上面代碼是EF實現的插入,很完善,將實現添加到實體集合,並使用SaveChanges()提交到數據庫,一個完善的數據插入流程完成,但一個問題來了如果我們的
業務操作不只是插入一張表,還有更新另一張表,怎么去實現呢?
public virtual void Modify(TEntity item) { _db.Set<TEntity>().Attach(item); _db.Entry(item).State = EntityState.Modified; this.SaveChanges(); }
上面為完整的更新動作是上面的代碼,現在有一個假設:
UserRepository類有方法Add,ProductRepository類有方法Modify,這時,這兩個方法進行組織,代碼可能是這樣:
...code
userRepository.Add(user);
userRepository.Modify(product);
...code
事實上,上面的代碼所執行的過程為:先插入用戶表,提交到SQL數據庫,再更新產品表,再提交到SQL數據庫,這時由於提交兩次,SQL端會產生兩個連接池,而如果兩個方法使用了TransactionScope事務塊,並且SQL服務器與WWW服務器在不同的電腦上,會觸發多於的分布式事務(這是可以避免的),而我們知道,windows的MSDTC(分布式事務)服務是最不靠譜的。
如何解決這種情況呢,難道方法不該完整嗎?
什么事情都有解決的辦法,方法的完整性在系統設計上是沒有問題的,但有時,對於一個工作單元中有多個方法時,我們需要把這種完整性升級,將多個方法提升為一個整體,即多個方法的完整性問題,解決這個問題的關鍵在於,你的數據上下文是否為一個,你的submitChanges方法是否為一個。
IUnitWork嶄新的接口規范
/// <summary> /// 工作單元 /// 提供一個保存方法,它可以對調用層公開,為了減少連庫次數 /// </summary> public interface IUnitOfWork { /// <summary> /// 將操作提交到數據庫, /// </summary> void Save(); /// <summary> /// 是否不提交到數據庫,這只是在具體的repository類中的SaveChanges方法里用到的 /// 默認為false,即默認為提交到數據庫 /// </summary> /// <returns></returns> bool IsNotSubmit { get; set; } } /// <summary> /// 工作單元 /// 對泛型類型的支持 /// </summary> /// <typeparam name="T"></typeparam> public interface IUnitWork<T> : IUnitOfWork where T : class { }
看了上面的接口,不用我說,大家也知道其中的含義了,Save()為數據上下文提交,而IsNotSubmit表示是否要提交到數據庫,我們都知道bool類型對象的默認
值不false,所以,默認情況下,Add,Modify這些方法的提交動作都是true,即被提交到數據庫。
我們優化這時上面add與modify的方法如下:
Domain.Core.IUnitOfWork _iUnitWork = new backgroundEntities(); _iUnitWork.IsNotSubmit=true; userRepository(user); productRepository(product); _iUnitWork.Save();
OK, 上面的代碼所產生的效果就是,將兩條SQL語句發到SQL端 ,使用一個SQL連接池,不產生MSDTC服務。