EF架構~EF非同步改造之路~讓DbContextRepository去實現非同步介面

張佔嶺發表於2014-12-04

回到目錄

返回非同步與並行目錄

上一講中,我們定義了三個非同步操作介面,這回我們將對它進行實現,而有一個基礎知識需要大家清楚,那就是實現介面的方式,一般我們使用預設的方式(隱式實現),這種方法實現的介面方式均為public,即它可以脫離介面,而直接通過類物件去訪問,而當一個類繼承多個介面,而這些介面中都有相同的方法時,我們就需要顯示實現介面了,顯示實現的介面成員只能通過介面例項去訪問它,今天我們對DbContextRepository的改造就用到了這個特性。

基本關鍵字

async:用來標識這個方法為非同步方法

await:用在非同步方法中,它可以等待非同步方法的返回值,即用來阻塞主執行緒,迫使它等待非同步請求,當請求成功返回後,再執行下面的程式碼

Task:非同步返回的結果,它有泛型版本,Task表示返回為void,而使用泛型版本時Task<T>返回結果為型別T

EF6引入的非同步提交機制

 public virtual Task<int> SaveChangesAsync();

一般地,倉儲大叔習慣將系統方法變為自已的方法,這樣方便以後去維護,如向SaveChangesAsync方法新增個什麼日誌,事件之類的東西,所以,就有了自己的版本。

/// <summary>
        /// 非同步提交到資料庫
        /// </summary>
        protected async Task SaveChangesAsync()
        {
            try
            {
                await Db.SaveChangesAsync();
            }
            catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)//捕獲實體驗證異常
            {
                var sb = new StringBuilder();
                dbEx.EntityValidationErrors.First().ValidationErrors.ToList().ForEach(i =>
                {
                    sb.AppendFormat("屬性為:{0},資訊為:{1}\n\r", i.PropertyName, i.ErrorMessage);
                });
                if (Logger == null)
                    throw new Exception(sb.ToString());
                Logger(sb.ToString() + "處理時間:" + DateTime.Now);

            }
            catch (OptimisticConcurrencyException)//併發衝突異常
            {

            }
            catch (Exception ex)//捕獲所有異常
            {
                if (Logger == null)//如果沒有定義日誌功能,就把異常丟擲來吧
                    throw new Exception(ex.Message);
                Logger(ex.Message + "處理時間:" + DateTime.Now);
            }

對DbContextRepository進行改造

下面程式碼,選自倉儲大叔的DbContextRepository.cs檔案,它是顯式實現的非同步操作介面的,具體實現如下

#region 非同步操作-顯示實現的介面,只能為介面例項進行呼叫
        #region IExtensionRepositoryAsync<TEntity> 成員

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.Insert(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i =>
            {
                Db.Entry<TEntity>(i);
                Db.Set<TEntity>().Add(i);
            });
            await this.SaveChangesAsync();
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.Update(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i =>
            {
                Db.Set<TEntity>().Attach(i);
                Db.Entry(i).State = EntityState.Modified;
            });
            try
            {
                await this.SaveChangesAsync();
            }
            catch (OptimisticConcurrencyException)//併發衝突異常
            {
            }
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.Delete(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i =>
            {
                Db.Set<TEntity>().Attach(i);
                Db.Set<TEntity>().Remove(i);
            });
            await this.SaveChangesAsync();
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.BulkInsert(IEnumerable<TEntity> item, bool isRemoveIdentity)
        {
            await Task.Run(() =>
            {
                this.BulkInsert(item, isRemoveIdentity);
            });
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.BulkInsert(IEnumerable<TEntity> item)
        {
            await Task.Run(() =>
            {
                this.BulkInsert(item);
            });
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.BulkUpdate(IEnumerable<TEntity> item, params string[] fieldParams)
        {
            await Task.Run(() =>
            {
                this.BulkUpdate(item);
            });
        }

        async System.Threading.Tasks.Task IExtensionRepositoryAsync<TEntity>.BulkDelete(IEnumerable<TEntity> item)
        {
            await Task.Run(() =>
            {
                this.BulkDelete(item);
            });
        }

        #endregion

        #region IRepositoryAsync<TEntity> 成員


        async System.Threading.Tasks.Task IRepositoryAsync<TEntity>.Insert(TEntity item)
        {
            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Insert));
            Db.Entry<TEntity>(item);
            Db.Set<TEntity>().Add(item);
            await this.SaveChangesAsync();
            OnAfterSaved(new SavedEventArgs(item, SaveAction.Insert));
        }

        async System.Threading.Tasks.Task IRepositoryAsync<TEntity>.Delete(TEntity item)
        {
            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Delete));
            Db.Set<TEntity>().Attach(item);
            Db.Set<TEntity>().Remove(item);
            await this.SaveChangesAsync();
            OnAfterSaved(new SavedEventArgs(item, SaveAction.Delete));
        }

        async System.Threading.Tasks.Task IRepositoryAsync<TEntity>.Update(TEntity item)
        {
            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Update));
            Db.Set<TEntity>().Attach(item);
            Db.Entry(item).State = EntityState.Modified;
            try
            {
                await this.SaveChangesAsync();
            }
            catch (OptimisticConcurrencyException)//併發衝突異常
            {

            }

            OnAfterSaved(new SavedEventArgs(item, SaveAction.Update));
        }

        #endregion
        #endregion

好了,到目前為止我們對DbContextRepository的改造就結束了,下一講我們將介紹如何在具體專案中使用EF的非同步功能,敬請期待!

回到目錄 

返回非同步與並行目錄

相關文章