Подтвердить что ты не робот

Почему Entity Framework 6.x не кэширует результаты?

Возможно, я недопонимаю кэширование, что DbContext и DbSet делает, но у меня создалось впечатление, что есть некоторое кэширование, которое будет продолжаться. Я вижу поведение, которого я не ожидал бы при запуске следующего кода:

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, состоит в том, что сначала будет проверять локальный кеш, чтобы увидеть, существует ли этот объект перед запросом базы данных. Есть ли какой-то вариант конфигурации, который я здесь отсутствует?

4b9b3361

Ответ 1

Что @emcas88 пытается сказать, заключается в том, что EF будет проверять кеш только при использовании метода .Find на DbSet.

Использование .Single, .First, .Where и т.д. не будет кэшировать результаты, если вы не используете кэширование второго уровня.

Ответ 2

Это связано с тем, что при реализации методов экстензора используется метод Find контекста

contextName.YourTableName.Find()

чтобы сначала проверить кеш. Надеюсь, что это поможет.

Ответ 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.

Ответ 4

Взгляните на EF Docs, вы найдете там ответ:

Обратите внимание, что DbSet и IDbSet всегда создают запросы к базе данных и всегда будет включать обратную поездку в базу данных, даже если возвращаемые объекты уже существуют в контексте. Выполняется запрос. против базы данных, когда:

  • Он перечисляется оператором foreach (С#) или для каждого (Visual Basic).
  • Он перечисляется операцией сбора, такой как ToArray, ToDictionary или ToList.
  • Операторы LINQ, такие как First или Any, указаны в самой внешней части запроса.
  • Вызываются следующие методы: метод расширения Load на DbSet, DbEntityEntry.Reload и Database.ExecuteSqlCommand.

Ответ 5

EF6 не выполняет кеширование результатов. Чтобы кэшировать результаты, вам необходимо использовать кеш второго уровня. Посмотрите этот перспективный проект на CodePlex:

Кэширование второго уровня для EF 6.1

Имейте в виду, что если данные изменятся на db, вы не сразу узнаете об этом. Иногда это важно в зависимости от проекта.;)

Ответ 6

Это очень понятно на 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");
}