Cha*_*ion 5 linq caching entity-framework entity-framework-6
我在 EF6 中遇到了缓慢的 LINQ 查询编译问题。我知道 EF 会缓存 LINQ 查询的已编译查询计划,但是有一些问题(例如 Enumerable.Contains 会阻止缓存)。我想查看缓存以进行调试,以验证我的查询是否获得了正确的缓存。我怎样才能做到这一点?
注意:由于这纯粹是为了调试,我很高兴使用反射或其他不会在生产中使用的方法来回答。
您可以使用类似以下内容反映到缓存(在 EF 6.1.3 中):
var method = context.Database.GetType().GetMethod("CreateStoreItemCollection", BindingFlags.Instance | BindingFlags.NonPublic);
var storeItemsCollection = method.Invoke(context.Database, null);
var queryCacheManagerField = storeItemsCollection.GetType().GetField("_queryCacheManager", BindingFlags.Instance | BindingFlags.NonPublic);
var queryCacheManager = queryCacheManagerField.GetValue(storeItemsCollection);
var cacheField = queryCacheManager.GetType().GetField("_cacheData", BindingFlags.Instance | BindingFlags.NonPublic);
var cacheData = cacheField.GetValue(queryCacheManager) as ICollection;
foreach (var item in cacheData)
{
Console.WriteLine(item.ToString());
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,缓存中的所有项目都是internal类型(在System.Data.Entity.Core.Common.QueryCache命名空间中),因此从它们中获取有用的信息将需要更多的反思和探索。幸运的是,CompiledQueryCacheKey覆盖ToString因此它放弃了一些关于自身的(神秘的)信息。运行单个查询 ( Table.Count()) 后,上面的代码会输出这两个条目:
[System.Data.Entity.Core.Common.QueryCache.ShaperFactoryQueryCacheKey`1[System.Int32], System.Data.Entity.Core.Common.QueryCache.QueryCacheEntry]
[FUNC<Edm.Count(In Transient.collection[Edm.Int32(Nullable=True,DefaultValue=)](Nullable=True,DefaultValue=))>:ARGS(([Project](BV'LQ1'=([Scan](DashboardAutoContext.Organizations:Transient.collection[DashboardAuto.Organization(Nullable=True,DefaultValue=)]))(1:Edm.Int32(Nullable=True,DefaultValue=)))))|||AppendOnly|True, System.Data.Entity.Core.Common.QueryCache.QueryCacheEntry]
Run Code Online (Sandbox Code Playgroud)
祝你好运,弄清楚这意味着什么,或者当你有一堆条目时将事情关联起来。
我取得了一些成功的另一种策略是创建一个类,其中包含我可以DbContext.Database.Log在测试期间分配的方法。该类在看到“已打开连接...”消息时启动计时器,然后在看到“-- 正在执行...”消息时停止计时器。该时间大致相当于 EF 将 LINQ 查询编译为 SQL 所需的时间。如果您的查询正在被缓存,那么在第一次执行查询后,该时间将几乎为零;如果不缓存,时间将始终保持较高水平。
(不用说,您只想在测试环境中执行此操作。)
| 归档时间: |
|
| 查看次数: |
1527 次 |
| 最近记录: |