【问题标题】:Why does Entity Framework 6.x not cache results?为什么 Entity Framework 6.x 不缓存结果?
【发布时间】:2014-03-09 14:24:15
【问题描述】:

也许我误解了 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 获得的部分内容是,它会在查询数据库之前首先检查本地缓存以查看该对象是否存在。我在这里缺少某种配置选项吗?

【问题讨论】:

  • @Jonesy 我会更新它以提供更清晰的示例。
  • @Adriano 不幸的是,这个答案已有 5 年历史,并且指的是旧版本的 EF。

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


【解决方案1】:

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

除非您使用二级缓存,否则使用.Single.First.Where 等将不会缓存结果。

【讨论】:

  • 您知道在 EF6 中实现二级缓存的任何资源或已经完成的任何项目吗?
  • 如果你用谷歌搜索,你应该会找到一些。我隐约记得在 codeproject 上的一个,虽然它不适用于 EF6,但它可能会起作用,并且绝对是一个不错的起点。更好的解决方案是不必再次执行相同的查询。
  • 我对此的问题源于一个担忧,即如果我查询我的DbContext 并在DbSet 中加载一些实体,然后运行一个对该DbSet 有副作用的存储过程,我想确保我的“陈旧”实体不再存在。听起来我不需要担心这个。
  • EF 将缓存 .First 的结果由于Performance Considerations for Entity Framework 4, 5, and 6。暖查询使用缓存数据。我还有一个使用.Where 的代码,它从缓存中读取。也可能 EF 缓存 .Single
  • @mjalil 我认为您将结果缓存与元数据、视图和物化器缓存混淆了。只有.Find会在一级缓存中缓存实际查询结果。
【解决方案2】:

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

contextName.YourTableName.Find()

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

【讨论】:

  • 我不太清楚你的意思。
  • @MailmanOdd 我的意思是使用上下文的 Find 方法。该方法先检查缓存。
  • +1,这其实是正确答案。我认为不完美的英语不应该成为投反对票的理由。
  • 一点也不。下次更新您的答案而不是添加到 cmets 中,人们应该更有可能收回他们的反对票。
  • 虽然我知道Find 会先检查DbSet<T>.Local,但我认为这并不能真正回答我的问题。
【解决方案3】:

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

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");

您也可以将 FirstOrDefault 替换为 SingleOrDetfault。

【讨论】:

  • 我喜欢这个解决方案。只是一点点反馈:您错过了“DbSet queryable”之前的“this”,并且知道“Where(condition).FirstOrDefault()”与“.FirstOrDefault(condition)”相同。谢谢分享crys。
  • 非常有趣。但这也适用于延迟加载吗?
【解决方案4】:

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

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

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

【讨论】:

    【解决方案5】:

    EF6 不做开箱即用的结果缓存。为了缓存结果,您需要使用二级缓存。在 CodePlex 上查看这个有前途的项目:

    Second Level Caching for EF 6.1

    请记住,如果数据库上的数据发生变化,您不会立即知道。有时这很重要,具体取决于项目。 ;)

    【讨论】:

    【解决方案6】:

    在 MSDN 上很清楚。 请注意什么是 find

    [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");
    }
    

    【讨论】:

    • 这个问题是 5 年前提出的。该文档不存在。
    猜你喜欢
    • 2011-09-19
    • 2021-03-14
    • 1970-01-01
    • 2021-08-17
    • 2017-03-05
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 2014-05-16
    相关资源
    最近更新 更多