Кэширует ли EF сущности между различными экземплярами DbContext?
создает ли DbContext на запрос в Asp.net сделать EF только читать данные из своего кэша, или он запрашивает DB для всех наборов каждый раз? Я знаю о кэшировании метаданных на AppDomain, но как насчет только данных?
контекст: приложение сбора и визуализации данных с интерфейсом MVC4 + Web API не будет называть это "большим объемом", но многие запросы возвращают одни и те же наборы данных в более короткие сроки.
1 ответов
Entity Framework не имеет кэша данных на AppDomain, только кэш на экземпляр контекста.
если вы создаете новый контекст для каждого запроса или запроса, вы начинаете с пустым кэшем и EF будет получать данные из базы данных.
кроме того, термин "кэш для экземпляра контекста" может вводить в заблуждение, поскольку это не означает, что EF не будет запускать запросы к базе данных, если сущности уже загружены в кэш контекста. Как работает этот кэш и как вы можете использовать его (или нет) можно следующим образом:
-
запрос LINQ-to-Entities на
DbSet<T>
или вообще наIQueryable<T>
будет выполнять запрос базы данных, независимо от того, существуют ли объекты уже в контексте или нет. Но если сущность с тем же ключом, что и запрашиваемая сущность, уже существует в контексте, EF выбросит результат этого запроса и вернет кэшированный экземпляр сущности вызывающему объекту.он делает эту проверку, если сущность с тем же ключом существует после он выполнил запрос. (Для сложных запросов-например, запросов, содержащих
Include
- он не может сделать эту проверку раньше, потому что он не может знать, какие сущности и Ключевые значения будут возвращены.)это поведение по умолчанию (
MergeOption
isAppendOnly
). Вы можете изменить это поведение наOverwriteChanges
и другие варианты, я считаю, но ни один из них не избежит того, что запросы LINQ всегда выдают базу данных запросы. для запроса сущности только по ее ключу вы можете использовать
GetObjectByKey
илиFind
(СDbContext
), который сначала проверит, кэшируется ли сущность с этим ключом в контексте, а затем вернет этот кэшированный объект. Если нет, он запустит запрос базы данных для его загрузки.-
вы можете запросить ChangeTracker EF, он особенно хорошо поддерживается с
DbContext
где у вас есть доступ к контексту кэш черезDbSet<T>.Local
коллекция.проблема здесь в том, что нет логики для автоматического запроса базы данных, если запрос на
Local
не возвращает результат. Вы должны написать эту логику вручную. Еще большая проблема заключается в том, что запрос наLocal
является LINQ-to-Objects, а не LINQ-to-Entities (Local
не выполнятьIQueryable<T>
, толькоIEnumerable<T>
), поэтому вам часто приходится переписывать свои запросы, чтобы действовать наLocal
- например, вы не можете использоватьInclude
здесь, ваш не может использовать любойEntityFunctions
, вы получите различное поведение для сравнения строк относительно регистра и т. д., п.