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