EF 6已经自带缓存机制,我们是否需要外部缓存机制?

3
我最近接触到了Entity Framework 6的缓存机制caching mechanism。正如我们从this article中了解到的那样,它是以一级方式实现的。
我们的系统使用EF 6(Code First)和MemoryCache来提高性能。
我们使用MemoryCache的主要原因是因为我们需要在每个页面请求上执行一个强烈的查询。由于存在客户端回调,我们在每个页面请求上执行此查询x3次(在最坏的情况下)。
我想知道如果EF 6已经使用了缓存机制,我们是否仍然需要使用MemoryCache机制。
值得一提的是,我们没有使用任何特殊的缓存功能或缓存依赖项。只是一个简单的MemoryCache带有超时。
2个回答

5
EF在上下文中缓存实体,这并不能完全替代“真正的”缓存,原因如下:
  1. You should not reuse EF context for more that one logical operation, because EF context represents unit of work, and so should be used according to this pattern. Also, even if you for some reason reuse context in multiple operations - you absolutely cannot do that in multi-threaded environment, like web server application.

  2. It does not prevent you from making multiple queries for the same data to your database, for example:

    var entity1 = ctx.Entities.Where(c => c.Id == 1).First();
    var entity2 = ctx.Entities.Where(c => c.Id == 1).First();
    

    This will still execute two queries to your database, despite the fact that query is the same and returns the same entity. So nothing is really "cached" in usual sense here. Note however, that both queries will return the same entity, even if database row has been changed between two queries. That is what is meant by EF context "caching". It will execute database query two times, but second time, while evaluating the result, it will notice that there is already entity with the same key attached to the context. So it will return this existing ("cached") entity instead, and will ignore new values (if any) returned by the second query. That behaviour is additional reason to not reuse the context between multiple operations (though you should not do it anyway).

如果您想减轻数据库的负担 - 您需要使用适合您需求的二级缓存(从简单的InMemoryCache到缓存EF提供程序再到分布式memcached实例)。


谢谢您的回复。我对第二部分感到惊讶,如果我执行一次查询,然后更改数据库中的值并再次执行相同的查询,它会带来相同的结果,而没有任何更改。这在第二次查询中是否仍然涉及到数据库?尽管它给了我未更新的数据? - Jacob
@Jacob 我更新了那部分来回答你的问题,希望足够清晰。如果你仍然对此有些担忧 - 很容易验证自己 - 只需设置日志记录(例如 context.Database.Log = Console.WriteLine),然后执行相同的查询两次,你会看到执行了两个数据库查询。 - Evk
最好的解释。非常感谢! - Jacob
我已经检查过了,你是正确的,它确实在第二次访问时进入了数据库。你有任何想法为什么EF会这样做,如果它不打算使用结果,它可以在进行不必要的访问之前估计出来吗? - BornToCode

4

EF只实现了所谓的实体一级缓存,它存储了在上下文生命周期内检索过的实体,因此当您第二次请求该实体时,它会从上下文返回该实体。您需要的是第二级缓存,但EF没有实现这些功能。例如,NCache实现了一个出色的缓存架构和一个开箱即用的EF第二级缓存提供程序。但它不在其开源版本中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接