轉帖|使用教程|編輯:龔雪|2015-09-29 15:55:17.000|閱讀 483 次
概述:EntityFramework DynamicFilters是我們創(chuàng)建全局的,針對實體框架查詢的過慮器,這些過濾器會自動應用于每一個查詢。能被用于支持多租戶,軟刪除,等等。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
一、EntityFramework DynamicFilters 是什么,它能做什么?
EntityFramework DynamicFilters是一個開源項目。文章結尾有下載它的源碼地址。顧名思義,它為我們做的事,就是幫我們動態(tài)過濾數(shù)據(jù)。為了照顧初學者,我們從頭道來。
1、何為數(shù)據(jù)過濾?
數(shù)據(jù)過濾說簡單點,就是去掉我們不想要的數(shù)據(jù)。SQL語句中的where從句,Linq中的where從句,還有擴展方法Where,就是完成這件光榮任務的。
2、何為動態(tài)?
動態(tài)的意思就是不死板地應用我們所寫的條件,比如,我們在一個地方寫了where從句,它只能用于這次查詢,下次遇到相似的情況時,我們還得老老實實的寫 where xxx=xxx。很長的一段時間,我們一直這樣,很和諧地使用著這種方法。突然有一天,抓了抓頭:如果類似的情況,能自動加上相應的過慮條件,或是應用相應的規(guī)則,該有多好?于是就有動態(tài)。當然這里的動態(tài),只是我們面對問題的一個方面。
3、廢話半天,它到底能做什么,具體點,好不?
它可以為我們創(chuàng)建全局的,針對實體框架查詢的過慮器,這些過濾器會自動應用于每一個查詢。能被用于支持多租戶,軟刪除,等等。過濾器能通過返回布爾類型的Linq表達式來創(chuàng)建,同時還支持Contains()操作符(方法)。目前支持的數(shù)據(jù)庫有MS SQL Server(包含 Azure),MySql,Oracle。
二、 沒有它時,我們是怎么做的?
我們以軟刪除(不是真正意義上的刪除數(shù)據(jù),只是在相應的記錄上作一個刪除標識)為例。正因為數(shù)據(jù)沒有被真正地刪除,只是被我們用一個標識給標記起來了,那么,我們就得在每一個查詢的地方加上一個條件(過濾掉標記為刪除的數(shù)據(jù)),代碼可能長成這樣:
var blogs = context.BlogEntries.Where(b => b.IsDeleted == false).ToList();
上面的代碼就不用多解釋了,相信你能看明白。 如果是sql 語句,你可能會說,這有什么難的,我找一個地方,把所有的查詢拼接上這個條件不就OK。 確實如此,但,這里只是拿這個簡單的場景來作為示例,復雜的場景呢?其次,Linq表達式拼接條件 ,不是像字符串那樣隨心所欲,至少很大一部分人是這樣,當然也包含我。每一個查詢都手工加上這樣的條件,不光是工作量增加了,可維護性降低了,還分散了我們的核心業(yè)務邏輯的注意力。
三、EntityFramework DynamicFilters給我們帶來了改變
當然,它只是眾多解決方案之一,只是作者無私的分享出來了,沒把它當成寶供在自己的電腦里。 我只需要在上下文DbContext的OnModelCreating 方法中添加過濾器。代碼如下:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //限制所有針對BlogEntry查詢的過慮(只獲取未刪除的) //這里的全局過慮,使用了委托,以便在每次需要計算值 //重要:如果值使用的是一個委托,請確保它在你的應用中是全局的, modelBuilder.Filter("BlogEntryFilter", (BlogEntry b, bool isDeleted) => (b.IsDeleted == isDeleted), () => false); }
就這樣,它就會在我們每一個關于Blog實體的查詢中添加上條件(b => b.IsDeleted == false)。我們無需關心它如何添加這個條件,使用的地方,完全透明,就像沒有它一樣。示例代碼如下:
/// <summary> /// 查詢 /// </summary> /// <param name="context"></param> /// <param name="userName"></param> private static void Query(ExampleContext context, string userName) { var account = context.Accounts .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName); Console.WriteLine("賬號{0}的博客有:",userName); if (account == null) return; foreach (var blog in account.BlogEntries) { Console.WriteLine("{0}",blog.Id); } }
但需要注意的是,如果在同一個上下文DbContext實例中,運用過慮器之前,過慮器有被禁用過,而數(shù)據(jù)被緩存時,過濾器就不會起任何效果,所有使用時,你一定要避免在同一個上下文中因更改過濾器而影響結果的情況。
如果你在某種情況下不想使用過慮器時,你可以使用如下代碼將其禁用:
//禁用過濾器 context.DisableFilter("BlogEntryFilter");
注意:禁用只對當前上下文DbContext實例有效,不影響別的上下文實例。如果你想對所有的上下文實例有效時,可以在 OnModelCreating方法中使用全局禁用函數(shù):
//全局禁用過濾器
modelBuilder.DisableFilterGlobally("BlogEntryFilter");
啟用的代碼類似,這里就不多少了,直接看代碼:
//啟用過濾器 context.EnableFilter("BlogEntryFilter"); context.EnableAllFilters();
說了這么多,我們來看看運用過濾器的效果吧,代碼如下:
class Program { static void Main(string[] args) { // 過濾器默認啟用 var context = new ExampleContext(); Console.WriteLine(" 使用過濾器BlogEntryFilter進行查詢"); Query(context, "homer"); //禁用過濾器 context.DisableFilter("BlogEntryFilter"); Console.WriteLine(" 禁用過濾器BlogEntryFilter進行查詢"); Query(context, "homer"); Console.ReadLine(); } /// <summary> /// 查詢 /// </summary> /// <param name="context"></param> /// <param name="userName"></param> private static void Query(ExampleContext context, string userName) { var account = context.Accounts .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName); Console.WriteLine("賬號{0}的博客有:",userName); if (account == null) return; foreach (var blog in account.BlogEntries) { Console.WriteLine("{0}",blog.Id); } } }
四、EntityFramework DynamicFilters原理概述
它是通過在對象 DbModelBuilder 上添加擴展方法Filter實現(xiàn)的,核心代碼如下:
1 private static void Filter<TEntity>(DbModelBuilder modelBuilder, string filterName, LambdaExpression predicate, params object[] valueList) 2 { 3 InitializeDynamicFilters(null); 4 5 filterName = ScrubFilterName(filterName); 6 7 modelBuilder.Conventions.Add(new DynamicFilterConvention(filterName, typeof(TEntity), predicate)); 8 9 // Always add the filter to _GlobalParameterValues - need it to be able to disable it 10 _GlobalParameterValues.TryAdd(filterName, new DynamicFilterParameters()); 11 12 int numParams = predicate.Parameters == null ? 0 : predicate.Parameters.Count; 13 int numValues = valueList == null ? 0 : valueList.Length; 14 for (int i = 1; i < numParams; i++) 15 { 16 object value = ((i - 1) < numValues) ? valueList[i - 1] : null; 17 SetFilterGlobalParameterValue(null, filterName, predicate.Parameters[i].Name, value); 18 } 19 }
文中示例源代碼下載地址://files.cnblogs.com/files/VolcanoCloud/EFDynamicFilterDemo.rar
本文轉自《付燦的技術博客》
本站文章除注明轉載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn