天天看點

EF架構~EF異步改造之路~讓DbContextRepository去實作異步接口

回到目錄

傳回異步與并行目錄

上一講中,我們定義了三個異步操作接口,這回我們将對它進行實作,而有一個基礎知識需要大家清楚,那就是實作接口的方式,一般我們使用預設的方式(隐式實作),這種方法實作的接口方式均為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的異步功能,敬請期待!

回到目錄 

作者:倉儲大叔,張占嶺,

榮譽:微軟MVP

QQ:853066980

支付寶掃一掃,為大叔打賞!

EF架構~EF異步改造之路~讓DbContextRepository去實作異步接口