2013-06-11 8 views
7

Создает ли DbContext для каждого запроса в Asp.net, чтобы EF только считывал данные из своего кеша или каждый раз запрашивал БД для всех наборов? Я знаю о кешировании метаданных в AppDomain, но как насчет данных?Включает ли EF объекты между различными экземплярами DbContext?

Контекст: приложение для сбора данных и визуализации с интерфейсом MVC4 + Web API не будет называть этот «большой объем», но многие запросы возвращают одни и те же данные в более короткие временные рамки.

+0

Я не думаю, что данные кэшируются в сущности, это всегда запрос DB –

ответ

13

У Entity Framework нет кэша данных на AppDomain, только кеш на экземпляр контекста.

Если вы создаете новый контекст для каждого запроса или запроса, вы начинаете с пустого кеша, а EF будет извлекать данные из базы данных.

Кроме того, термин «кеш на экземпляр контекста» может вводить в заблуждение, поскольку это не означает, что EF не будет запускать запросы к базе данных, если сущности уже загружены в кэш контекста. То, как этот кэш работает и как вы можете использовать его (или нет) является следующее:

  • Каждый LINQ к Entities запрос на DbSet<T> или вообще на IQueryable<T> будет выполнить запрос к базе данных, независимо от того, существуют ли сущности в контексте или нет. Но если объект с тем же ключом, что и запрашиваемый объект, уже существует в контексте, EF выкинет результат этого запроса и вернет экземпляр кэшированного объекта обратно вызывающему.

    Это проверяет, существует ли объект с тем же ключом после он выполнил запрос. (Для сложных запросов - например запросов, которые содержат Include. - он не может сделать эту проверку, прежде чем, потому что он не может знать, какие будут возвращены сущности и значения ключей)

    Это поведение по умолчанию (MergeOption является AppendOnly). Вы можете изменить это поведение на OverwriteChanges и другие варианты, я полагаю, но ни один из них не позволит избежать запросов LINQ, которые всегда вызывают запросы к базе данных.

  • Для запрашивая объект только ее ключом вы можете использовать GetObjectByKey или FindDbContext), который будет проверять первый, если объект с помощью этого ключа уже кэшируются в контексте, а затем вернуть этот объект в кэше. Если нет, он будет запускать запрос базы данных для его загрузки.

  • Вы можете запросить ET ChangeTracker, особенно хорошо поддерживается с DbContext, где у вас есть доступ к кешу контекста через коллекцию DbSet<T>.Local.

    Проблема заключается в том, что нет никакой логики для автоматического запроса базы данных, если запрос на Local не возвращает результат. Вы должны написать эту логику вручную. Еще большая проблема заключается в том, что запрос на Local является LINQ-to-Objects, а не LINQ-to-Entities (Local не реализует IQueryable<T>, только IEnumerable<T>), поэтому вам часто приходится переписывать свои запросы, чтобы действовать на Local - например вы не можете использовать Include здесь, вы не можете использовать любой EntityFunctions, вы получите различное поведение для сравнения строк в отношении чувствительности к регистру, и т.д. и т.п.

+0

Спасибо за великолепное объяснение.До сих пор я полностью упустил тот факт, что кешированная версия может использоваться, даже если запросы выдаются против базы данных. Я использовал SQL Server Profiler и видел запросы, которые не возвращали свежие данные в мое приложение !? Наконец, я узнал, что мой пользовательский MemberhipProvider был сохранен структурой между запросом и таким образом был экземпляр контекста, который он хранил. Другой код работал в контекстах, и все было полностью запутано. –

Смежные вопросы