基礎才(cai)是重中之重~泛型類的(de)靜態構造方法(fa)可不(bu)是只執行一次呀
最近做了一個數據庫的讀寫分離項目,使用到了DbCommand攔(lan)截器,在程序開發過程中沒有發現(xian)什么特別的(de)(de)問(wen)題(ti)(ti),而當(dang)開發完成后,在進行(xing)測試階段時(shi),一(yi)個(ge)(ge)偶然(ran)的(de)(de)機會讓我發現(xian)了,原來我的(de)(de)攔(lan)截器注入(ru)不(bu)只是注入(ru)一(yi)次,而是每種類型的(de)(de)倉儲都會注入(ru)一(yi)次,這(zhe)個(ge)(ge)問(wen)題(ti)(ti)事實(shi)上是相關嚴(yan)重(zhong)的(de)(de)一(yi)件事,如果你的(de)(de)攔(lan)截器處理邏輯很(hen)多,那么,這(zhe)將(jiang)是非常消耗性(xing)能(neng)的(de)(de)。
原(yuan)因,靜態(tai)構造方法對(dui)泛(fan)型類不(bu)是唯一的(de),而是相互獨立(li)的(de)
public abstract class DbContextRepository<TEntity> : ISpecificationRepository<TEntity> where TEntity : class { #region Constructors /// <summary> /// 靜態構造(zao)方(fang)法對每(mei)個TEntity是獨(du)立的,有多(duo)少類型初始化(hua),這(zhe)個方(fang)法就執行多(duo)少次 /// </summary> static DbContextRepository() { //泛型類的靜態構造方(fang)法... } }
結果,每個(ge)類(lei)型初始化時,都會(hui)向攔截器(qi)字典(dian)中添(tian)加一條
IRepository<WebManageUsers> userWrite = new BackgroundRepositoryBase<WebManageUsers>(db); IRepository<WebManageMenus> menuWrite = new BackgroundRepositoryBase<WebManageMenus>(db); //每次(ci)初始化,靜態構造(zao)方法都會被執(zhi)行
事實上,這是可以理解的,因為泛型類本身就是未定義的,當你初始化它時,具體的類型才被運行時得知,這時,在第一次使用它時,“這個類”的靜態構造方法才會被執行,這是完全沒問題的,可能開發人員有時就忽略了這一點。
解決,使(shi)用反(fan)射來實現(xian)自(zi)己的按需添加(jia)
/// <summary> /// DbCommand攔截器擴展 /// </summary> public static class DbCommandInterceptorExtensions { /// <summary> /// 將DbCommand的(de)攔(lan)截器以單例的(de)形式添加到DbInterception靜(jing)態對象中 /// </summary> /// <param name="action"></param> public static void UsingSingletonInterceptor(DbCommandInterceptor interceptor) { #region SQL語句攔截器,攔截器只加載一次 var property = typeof(DbCommandDispatcher).GetProperty("InternalDispatcher", BindingFlags.Instance | BindingFlags.NonPublic); if (property != null) { var val = property.GetValue(System.Data.Entity.Infrastructure.Interception.DbInterception.Dispatch.Command); if (val != null) { var list = val.GetType().GetField("_interceptors", BindingFlags.Instance | BindingFlags.NonPublic); if (list != null) { var listVal = list.GetValue(val) as List<System.Data.Entity.Infrastructure.Interception.IDbCommandInterceptor>; if (listVal != null) { if (listVal.FirstOrDefault(i => i.ToString() == interceptor.GetType().ToString()) == null) { System.Data.Entity.Infrastructure.Interception.DbInterception.Add(interceptor); } } } } } #endregion } }
調用這很方便
EntityFrameworks.Data.Core.Extensions.DbCommandInterceptorExtensions.UsingSingletonInterceptor(new CommandInterceptor());
OK,這樣我們的每個攔截器在DbInterception對象中都只會出現一次,再也不會出現一個攔截器被(bei)執行多次的情況(kuang)了,呵(he)呵(he)。