這個標題很有意思,關系表插入,就是說主表和外表鍵在插入時,可能會有同步插的情況,如在建立主表時,擴展表需要同步完成數據的初始化工作,而對於多表插入時,我們為了保證數據的一致性會針它寫在事務中,而對於.net中的事件,它在一些情況下,會不那么單純,對於ef和linq to sql來說,你的事務如果出現多次提交動作(submitchange | savechanges),那么,.net這邊會把它提升為分布式事務(MSDTC),即.net認為,對於一個數據表的操作,不會出現多個savechanges,OK,這個可以解釋的通,一個數據庫,一個提交,這是符合性能要求的,呵呵,但對於我們的架構來說,有時一疏忽,就違背了.net的這個原則,如,我們封裝的Insert方法,可能是這樣的
public virtual void Insert(TEntity item) { Db.Entry<TEntity>(item); Db.Set<TEntity>().Add(item); this.SaveChanges(); }
這個代碼也沒有問題,在一個插入動作完成后,系統由SaveChanges方法完成一次提交,正是由於這樣的代碼,所以我們的麻煩就來了,如果是對兩個表的操作嗎?
aRepository.Insert(a);
bRepository.Insert(b);
什么問題?數據一致性不能保證,因為沒有事務塊,呵呵,加上了再看看
using (TransactionScope trans = new TransactionScope()) { aRepository.Insert(a); bRepository.Insert(b); trans.Commit(); }
OK,感覺是沒有問題了,但細一想就會看出問題來了,因為我們封裝的insert會有提交動作,所以,在這個事務塊中,.net會被認識是一個MSDTC(分布式的事務),原因是提交了多次,而如果你沒有打開msdtc服務的話,就會出現下面的黃屏了
注意:系統觸發分布式事務的前提是你的WEB服務器與數據庫服務器分別部署在兩個服務器上,一台不會出現這個問題的。
OK,這個MSDTC是怎么一回事,不是今天要說的重要,如果想學習MSDTC,請看我的這些文章:
第二十六回 將不確定變為確定~transactionscope何時提升為分布式事務?
第二十七回 將不確定變為確定~transactionscope何時提升為分布式事務~續
第二十八回 將不確定變為確定~transactionscope何時提升為分布式事務~再續(避免引起不必要的MSDTC)
第二十九回 將不確定變為確定~transactionscope何時提升為分布式事務~大結局
今天我們要說的是在插入關系表時,怎樣使它不被提升為分布式事務,事實上,怎么做我們已經知道了,就是方法中只出現一個savechages,呵呵,而對於主表與擴展表來說,對於自增主鍵的主表,做起來就有些麻煩了,呵呵,我們還需要借助SQL函數來實現主鍵的獲取工作,當主鍵插入后,通過SQL函數得到新值,然后再為擴展表賦值,最后一些savechange()就可以了,具體我們看一下代碼:
int maxID = Convert.ToInt32(new TsingDa_NewLearningBarEntities()//當前表最大ID .Database.SqlQuery<decimal>("SELECT IDENT_CURRENT ('Classroom_Info')") .First()); using (TransactionScope trans = new TransactionScope()) { try { db.Entry<Classroom_Info>(entity); db.Set<Classroom_Info>().Add(entity); //綁定學生 entity.User_Classroom_R.ToList().ForEach(i => { i.ClassroomInfoID = maxID + 1; db.Entry<User_Classroom_R>(i); db.Set<User_Classroom_R>().Add(i); }); db.SaveChanges();//是否為msdtc就看它提交的次數 trans.Complete(); } catch (Exception) { trans.Dispose();//出現異常,事務手動釋放 throw; } }
而一次savechanges所產生的SQL也是我們可以接受的,與服務器連接池中開啟一個新連接,然后把語句一條一條的發過去,雖然不是一次性發送,但結果我們也是可以接受的,呵呵。
補充回復:
看了xiashengwang的 回復,我自己去試了一下,果然savechange將當前上下文中所有要提交的東西包在了一個事務塊里,出現異常后,自動完成callback,所以,對 於一個數據庫來說TransactionScope可以省去,而對於多個數據庫的操作,才需要使用TransactionScope,而對於何時將 TransactionScope提升為MSDTC的級別,到目前為止,我只能說,一個上下文的savechanges不會提升,多個 savechanges就會提升到msdtc,而矛盾是,一個savechanges的話,確實不需要外加TransactionScope塊了,呵呵, 這部分文章估計我還要繼續寫了,看看有沒有辦法在同一上下文多個savechanges操作時,不讓系統提升到MSTDC的級別,呵呵。