EF架構(gou)~數(shu)據分批批量提交
對于大數據量提交,包括插入,更新和刪除,我始終不建議用EF自帶的方法,因為它會增加與數據庫的交互次數,一般地,EF的一個上下文在提交時會打開一個數據連接,然后把轉換成的(de)SQL語句一條(tiao)一條(tiao)的(de)發到(dao)數據庫端,然后去(qu)提交(jiao),試想,如果(guo)你(ni)的(de)(de)(de)數(shu)(shu)據(ju)量達(da)到(dao)萬級別(更(geng)不用說百(bai)萬,千萬數(shu)(shu)據(ju)了(le)),那對數(shu)(shu)據(ju)庫的(de)(de)(de)壓力是(shi)很大(da)的(de)(de)(de),所以,我(wo)將EF批(pi)量操作語(yu)句(ju)進行(xing)了(le)改版,并(bing)起名為BulkInsert,BulkUpdate和BulkDelete,事實上,在(zai)我(wo)之(zhi)前(qian)的(de)(de)(de)版本(ben)中并(bing)沒(mei)有(you)涉及到(dao)批(pi)次(ci)(ci)提交(jiao)的(de)(de)(de)概(gai)念,直到(dao)遇(yu)到(dao)了(le)實際的(de)(de)(de)問題(ti),當(dang)你(ni)使用BulkInsert時,如果(guo)數(shu)(shu)據(ju)達(da)到(dao)4萬之(zhi)前(qian),那在(zai)SQL的(de)(de)(de)解釋時,也是(shi)很有(you)壓力的(de)(de)(de),有(you)多(duo)情(qing)況下會超時,當(dang)然這與(yu)你(ni)的(de)(de)(de)數(shu)(shu)據(ju)庫服務器有(you)關,但(dan)為了(le)性能與(yu)安全,我(wo)還(huan)是(shi)決(jue)定(ding)將Bulk操作變為分批(pi)提交(jiao),即將4W進行(xing)分解,分用1W數(shu)(shu)據(ju)量提交(jiao)一次(ci)(ci),這樣(yang),對數(shu)(shu)據(ju)庫的(de)(de)(de)壓力就小(xiao)一些。看看我(wo)的(de)(de)(de)改版吧。
public void BulkInsert(IEnumerable<TEntity> item) { DataPageProcess(item, (currentItems) => { ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永不(bu)超時 _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Insert)); }); } public void BulkDelete(IEnumerable<TEntity> item) { DataPageProcess(item, (currentItems) => { ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永(yong)不(bu)超時 _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Delete)); }); } public void BulkUpdate(IEnumerable<TEntity> item) { DataPageProcess(item, (currentItems) => { ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永(yong)不超時 _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Update)); }); }
/// <summary> /// 分頁(ye)進行數據(ju)提交的邏輯 /// </summary> /// <param name="item">原列表</param> /// <param name="method">處(chu)理方法</param> /// <param name="currentItem">要進行處理的新列表</param> private void DataPageProcess(IEnumerable<TEntity> item, Action<IEnumerable<TEntity>> method) { if (item != null && item.Count() > 0) { DataTotalCount = item.Count(); this.DataTotalPages = item.Count() / DataPageSize; if (DataTotalCount % DataPageSize > 0) DataTotalPages += 1; for (int pageIndex = 1; pageIndex <= DataTotalPages; pageIndex++) { var currentItems = item.Skip((pageIndex - 1) * DataPageSize).Take(DataPageSize).ToList(); method(currentItems); } } }
我們可以看到,改版后的方法,沒有直接把集合item傳遞給方法ExecuteSqlCommand去執行,而去調(diao)用了一個(ge)方法,這個(ge)方法然后傳入(ru)一個(ge)委(wei)托,然這個(ge)委(wei)托的
輸入參數是一個分頁的數據集合,這時你的ExecuteSqlCommand方法接入的集(ji)合參數將(jiang)是一個分了(le)頁之后的小集(ji)合,呵(he)呵(he)。
對于(yu)一次提交的(de)數(shu)量,你可以在類中(zhong)去(qu)定義,它類似于(yu)分頁(ye),所以,我通常叫這個方法為數(shu)據分頁(ye)提交!
#region Fields /// <summary> /// 數(shu)據總(zong)數(shu) /// </summary> int DataTotalCount = 0; /// <summary> /// 數(shu)據總頁數(shu) /// </summary> int DataTotalPages = 0; /// <summary> /// 數據頁面(mian)大小(每次向數據庫提交的記錄(lu)數) /// </summary> int DataPageSize = 10000; #endregion
如果你希望得到BlukInsert的完整方法,請關注本人的EF架構系列