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