日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
EFCodeFirst:二級(jí)緩存

一、前言

今天我們來談?wù)凟F的緩存問題。

緩存對(duì)于一個(gè)系統(tǒng)來說至關(guān)重要,但是是EF到版本6了仍然沒有見到有支持查詢結(jié)果緩存機(jī)制的跡象。EF4開始會(huì)把查詢語句編譯成存儲(chǔ)過程緩存在Sql Server中,據(jù)說EF6中對(duì)此做了改進(jìn),會(huì)把Linq To Entities 的查詢條件直接編譯緩存在EF中。但是這些都是只是對(duì)查詢條件做了緩存,而不是緩存查詢的結(jié)果集(DbSet.Find(object key)那個(gè)雖然走了DbSet.Local數(shù)據(jù)集,但也僅支持通過主鍵查找單個(gè)實(shí)體的情況,很有局限性),沒有達(dá)到我們想要的效果。

EF不加緩存功能,可能也有另外的考慮吧,這里不去猜測(cè)。雖然EF團(tuán)隊(duì)沒有在EF中加入緩存功能,但已經(jīng)給出的緩存功能的擴(kuò)展,這就是Community Entity Framework Provider Wrappers,這個(gè)擴(kuò)展的工作原理由下圖可以清晰的了解:

 該擴(kuò)展提供了跟蹤SQL運(yùn)行日志與SQJ結(jié)果集緩存的功能,這里,我們只用到它的緩存功能來為EF建立二級(jí)緩存的支持。

二、緩存設(shè)計(jì)

(一) 引用EFProviderWrappers

如下圖,在NuGet中只提供了Entity Framework Provider Wrapper Toolkit(基礎(chǔ)類庫)與Entity Framework Tracing Provider(日志跟蹤)的下載,很遺憾的并沒有提供 Entity Framework Caching Provider(緩存)。

我們只能自己動(dòng)手來引用了,這里提供幾種思路:

  • 到 http://code.msdn.microsoft.com/EFProviderWrappers 下載代碼,自行編譯,然后在項(xiàng)目GMF.Component.Data項(xiàng)目中手動(dòng)引用EFProviderWrapperToolkit.dll與EFCachingProvider.dll文件。
  • EFProviderWrapperToolkit由NuGet下載,EFCachingProvider手動(dòng)引用。

我是覺得兩種思路都挺麻煩的,這個(gè)擴(kuò)展的代碼貌似已經(jīng)不更新了(3/18/2011),而且在GMF.Component.Data中額外的引用兩個(gè)程序集也是個(gè)麻煩事,于是我用下面的方法來引用:

在GMF.Component.Data項(xiàng)目中新建兩個(gè)文件夾,把以上源代碼中的兩個(gè)工程以文件夾的形式包含到項(xiàng)目中。

這樣,似乎更干凈利落,如圖:

(二) 緩存代碼分析及整合

1. 關(guān)鍵代碼簡(jiǎn)介

在EFCachingProvider中,我們要用到的核心類有三個(gè):

  • ICache:緩存緩存基類,系統(tǒng)中實(shí)現(xiàn)了一個(gè)內(nèi)存緩存類(InMemoryCache),適用于單臺(tái)服務(wù)器的緩存實(shí)現(xiàn),如果要實(shí)現(xiàn)分布式緩存,可以從這個(gè)基類進(jìn)行擴(kuò)展。
    • InMemoryCache:內(nèi)存緩存實(shí)現(xiàn)類,內(nèi)部使用了一個(gè)Dictionary作為緩存容器,以查詢的SQL語句及參數(shù)的連接字符串(或其MD5值)為鍵(EFCachingCommands.cs類中定義)。還包含了緩存命中、緩存項(xiàng)數(shù)量等數(shù)據(jù)的統(tǒng)計(jì)及緩存清理功能。
  • CachingPolicy:緩存策略基類,定義了當(dāng)前實(shí)體是否可緩存(CanBeCached)、定義緩存緩存數(shù)(GetCacheableRows)、緩存項(xiàng)滑動(dòng)過期與絕對(duì)過期時(shí)間(GetExpirationTimeout)等功能,并默認(rèn)了絕對(duì)過期時(shí)間為永不過期(DateTime.MaxValue)。
    • NoCachingPolicy:不緩存策略,禁用緩存功能。
    • CacheAllPolicy:緩存所有數(shù)據(jù)策略,緩存項(xiàng)最大數(shù)量為int.MaxValue。
    • CustomCachingPolicy:自定義緩存策略,使用了CacheableTables與NonCacheableTables兩個(gè)集合來表示數(shù)據(jù)類型是否可緩存的白名單與黑名單,這兩個(gè)名單將在重寫的CanBeCached方法中作為類型是否可緩存的驗(yàn)證依據(jù)。
  • EFCachingConnection:此類定義了類型為ICache,CachingPolicy的兩個(gè)屬性,分別用于接收上面據(jù)說的兩個(gè)擴(kuò)展點(diǎn)。

2. 應(yīng)用緩存擴(kuò)展

EF的DbContext上下文類有一個(gè)重載

public DbContext(DbConnection existingConnection, bool contextOwnsConnection) { }

需要的是DbConnection參數(shù),而EFCachingConnection正好是派生自DbConnection的,我們只需要構(gòu)建一個(gè)EFCachingConnection對(duì)象作為參數(shù)去構(gòu)造DbContext派生類的對(duì)象,即可完成緩存功能的注入(如本篇第一張圖所示)。這里,緩存專用的DbContext派生類只需要派生自原項(xiàng)目中定義的EFDbContext類。

 
 
 
 
  1. namespace GMF.Component.Data  
  2. {  
  3.     ///   
  4.     ///     啟用緩存的自定義EntityFramework數(shù)據(jù)訪問上下文  
  5.     ///   
  6.     [Export("EFCaching", typeof (DbContext))]  
  7.     public class EFCachingDbContext : EFDbContext  
  8.     {  
  9.         private static readonly InMemoryCache InMemoryCache = new InMemoryCache();  
  10.  
  11.         public EFCachingDbContext()  
  12.             : base(CreateConnectionWrapper("default")) { }  
  13.  
  14.         public EFCachingDbContext(string connectionStringName)  
  15.             : base(CreateConnectionWrapper(connectionStringName)) { }  
  16.  
  17.         ///   
  18.         ///     由數(shù)據(jù)庫連接串名稱創(chuàng)建連接對(duì)象  
  19.         ///   
  20.         /// 數(shù)據(jù)庫連接串名稱  
  21.         ///   
  22.         private static DbConnection CreateConnectionWrapper(string connectionStringName)  
  23.         {  
  24.             PublicHelper.CheckArgument(connectionStringName, "connectionStringName");  
  25.  
  26.             string providerInvariantName = "System.Data.SqlClient";  
  27.             string connectionString = null;  
  28.             ConnectionStringSettings connectionStringSetting = ConfigurationManager.ConnectionStrings[connectionStringName];  
  29.             if (connectionStringSetting != null)  
  30.             {  
  31.                 providerInvariantName = connectionStringSetting.ProviderName;  
  32.                 connectionString = connectionStringSetting.ConnectionString;  
  33.             }  
  34.             if (connectionString == null)  
  35.             {  
  36.                 throw PublicHelper.ThrowComponentException("名稱為“" + connectionStringName + "”數(shù)據(jù)庫連接串的ConnectionString值為空。");  
  37.             }  
  38.             string wrappedConnectionString = "wrappedProvider=" + providerInvariantName + ";" + connectionString;  
  39.             EFCachingConnection connection = new EFCachingConnection  
  40.             {  
  41.                 ConnectionString = wrappedConnectionString,  
  42.                 CachingPolicy = CachingPolicy.CacheAll,  
  43.                 Cache = InMemoryCache  
  44.             };  
  45.  
  46.             return connection;  
  47.         }  
  48.     }  

這里緩存策略使用了緩存所有數(shù)據(jù)(CacheAllPolicy)的策略,在實(shí)際項(xiàng)目中,最好自定義緩存策略,而不要使用這個(gè)策略,以免服務(wù)器內(nèi)存被撐爆。

#p#

我們?cè)趹?yīng)用程序配置(Web.Config或App.Config)中,添加一個(gè)名為“EntityFrameworkCachingEnabled”的AppSettings節(jié)點(diǎn),用來進(jìn)行啟用/禁用緩存的開關(guān)配置。

 
 
 
 
  1.  
  2.    ...  
  3.      
  4.    ...  
  5.    

另外,緩存擴(kuò)展還需要我們?cè)谂渲梦募刑砑尤缦鹿?jié)點(diǎn)的配置:

 
 
 
 
  1.  
  2.      
  3.        
  4.        
  5.      
  6.    

再來看看,怎樣使用“EntityFrameworkCachingEnabled”配置來控制緩存功能的開關(guān)。我們的設(shè)計(jì)中,DbContext對(duì)象的注入點(diǎn)為如下所示的Context屬性:

所以,我們只需要在UnitOfWorkContextBase的派生類中讀取 EntityFrameworkCachingEnabled 進(jìn)行切換即可。

 
 
 
 
  1. namespace GMF.Component.Data  
  2. {  
  3.     ///   
  4.     ///     數(shù)據(jù)單元操作類  
  5.     ///   
  6.     [Export(typeof (IUnitOfWork))]  
  7.     public class EFRepositoryContext : UnitOfWorkContextBase  
  8.     {  
  9.         ///   
  10.         ///     獲取 當(dāng)前使用的數(shù)據(jù)訪問上下文對(duì)象  
  11.         ///   
  12.         protected override DbContext Context  
  13.         {  
  14.             get 
  15.             {  
  16.                 bool secondCachingEnabled = ConfigurationManager.AppSettings["EntityFrameworkCachingEnabled"].CastTo(false);  
  17.                 return secondCachingEnabled ? EFCachingDbContext.Value : EFDbContext.Value;  
  18.             }  
  19.         }  
  20.  
  21.         [Import("EF", typeof (DbContext))]  
  22.         private Lazy EFDbContext { get; set; }  
  23.  
  24.         [Import("EFCaching", typeof(DbContext))]  
  25.         private Lazy EFCachingDbContext { get; set; }  
  26.     }  

注意,因?yàn)镋FDbContext與EFCachingDbContext兩個(gè)屬性只能同時(shí)用到其中之一,導(dǎo)入需要使用Lazy<>類型來包裝,這樣沒用到的屬性就不會(huì)實(shí)例化了。

下面,我們來測(cè)試一下緩存功能是否生效,就用上篇的那個(gè)翻頁列表吧。判斷標(biāo)準(zhǔn)為SQL Server Profiler是否有SQL語句執(zhí)行。為方便演示,這里在列表的下方顯示當(dāng)前的時(shí)間,以便與SQL Server Profiler中的時(shí)間進(jìn)行匹配。

 第1頁不計(jì)。

點(diǎn)擊第2頁,執(zhí)行了查詢:

點(diǎn)擊第3頁,執(zhí)行了查詢:

再回到第2頁,沒有執(zhí)行查詢:

點(diǎn)擊第4頁,執(zhí)行了查詢:

結(jié)論:重復(fù)第2頁的時(shí)候,數(shù)據(jù)已經(jīng)緩存了,沒有讀數(shù)據(jù)庫查詢數(shù)據(jù),說明緩存已經(jīng)生效了。

最后要提示的一點(diǎn):

帶緩存的上下文不能擔(dān)當(dāng)生成數(shù)據(jù)庫的職責(zé),因此在第一次運(yùn)行生成數(shù)據(jù)庫的時(shí)候,必須關(guān)閉緩存。

三、源碼獲取

為了讓大家能第一時(shí)間獲取到本架構(gòu)的最新代碼,也為了方便我對(duì)代碼的管理,本系列的源碼已加入微軟的開源項(xiàng)目網(wǎng)站 http://www.codeplex.com,地址為:

https://gmframework.codeplex.com/

原文鏈接:http://www.cnblogs.com/guomingfeng/p/mvc-ef-caching.html


本文題目:EFCodeFirst:二級(jí)緩存
網(wǎng)站URL:http://www.dlmjj.cn/article/cdjhodp.html