Кэширует ли 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 is AppendOnly). Вы можете изменить это поведение на OverwriteChanges и другие варианты, я считаю, но ни один из них не избежит того, что запросы LINQ всегда выдают базу данных запросы.

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

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

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