为什么Entity Framework 6.x没有缓存结果?

时间:2014-02-11 16:51:20

标签: c# entity-framework caching entity-framework-6

也许我误解了DbContextDbSet所做的缓存,但我的印象是有一些缓存会持续下去。当我运行以下代码时,我看到了我不会期望的行为:

var ctx = CreateAContext();
var sampleEntityId = ctx.SampleEntities.Select(i => i.Id)
                                       .Single(i => i == 3); //Calls DB as expected
var cachedEntityId = ctx.SampleEntities.Select(i => i.Id)
                                       .Single(i => i == 3); //Calls DB unexpectedly

这里发生了什么?我认为你从DbSet获得的部分内容是它首先检查本地缓存,以便在查询数据库之前查看该对象是否存在。我在这里缺少某种配置选项吗?

6 个答案:

答案 0 :(得分:39)

.Find是什么@emcas88 is trying to say只有在DbSet上使用.Single方法时,EF才会检查缓存。

除非您使用的是二级缓存,否则使用.First.Where,{{1}}等不会缓存结果。

答案 1 :(得分:28)

这是因为伸展方法的实现,使用了上下文的Find方法

contextName.YourTableName.Find()

首先验证缓存。希望它有所帮助。

答案 2 :(得分:22)

有时我会使用我的扩展方法:

using System.Linq;
using System.Linq.Expressions;

namespace System.Data.Entity
{
    public static class DbSetExtensions
    {
        public static TEntity FirstOrDefaultCache<TEntity>(this DbSet<TEntity> queryable, Expression<Func<TEntity, bool>> condition) 
            where TEntity : class
        {
            return queryable
                .Local.FirstOrDefault(condition.Compile()) // find in local cache
                   ?? queryable.FirstOrDefault(condition); // if local cache returns null check the db
        }
    }
}

用法:

db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name");

您也可以将SingleOrDefault替换为SingleOrDetfault。

答案 3 :(得分:11)

看看EF Docs,你会在那里找到答案:

  

请注意,DbSet和IDbSet始终会针对数据库创建查询   并且将始终涉及到数据库的往返,即使   返回的实体已存在于上下文中。执行查询   在以下情况下对数据库:

     
      
  • 它由 foreach (C#)或 For Each (Visual Basic)语句枚举。
  •   
  • 它由ToArrayToDictionaryToList等集合操作枚举。
  •   
  • FirstAny等LINQ运算符在查询的最外部指定。
  •   
  • 调用以下方法:LoadDbSetDbEntityEntry.Reload上的Database.ExecuteSqlCommand扩展方法。
  •   

答案 4 :(得分:7)

EF6不会执行缓存ootb的结果。要缓存结果,您需要使用二级缓存。在CodePlex上看到这个有前景的项目:

Second Level Caching for EF 6.1

请记住,如果数据库中的数据发生更改,您将无法立即了解它。有时这取决于项目很重要。 ;)

答案 5 :(得分:-1)

在MSDN上非常清楚。 请注意找到的内容

[https://docs.microsoft.com/en-us/ef/ef6/querying/][1]


using (var context = new BloggingContext())
{
    // Will hit the database
    var blog = context.Blogs.Find(3);

    // Will return the same instance without hitting the database
    var blogAgain = context.Blogs.Find(3);

    context.Blogs.Add(new Blog { Id = -1 });

    // Will find the new blog even though it does not exist in the database
    var newBlog = context.Blogs.Find(-1);

    // Will find a User which has a string primary key
    var user = context.Users.Find("johndoe1987");
}