回到目錄
傳回異步與并行目錄
上一講中,我們定義了三個異步操作接口,這回我們将對它進行實作,而有一個基礎知識需要大家清楚,那就是實作接口的方式,一般我們使用預設的方式(隐式實作),這種方法實作的接口方式均為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
支付寶掃一掃,為大叔打賞!
