EF кешира ли обекти между различни екземпляри на DbContext?

Създаването на DbContext на заявка в Asp.net кара ли EF да чете само данните от своя кеш или всеки път прави заявка в DB за целите набори? Знам за кеширането на метаданни за AppDomain, но какво да кажем само за данните?

Контекст: приложение за събиране на данни и визуализация с интерфейс MVC4 + Web API, не бих нарекъл това „голям обем“, но много заявки връщат същите набори от данни в някакъв по-кратък период от време.


person mrówa    schedule 11.06.2013    source източник
comment
Не мисля, че данните се кешират в обекти, винаги е DB за заявки   -  person Jalpesh Vadgama    schedule 11.06.2013


Отговори (1)


Entity Framework няма кеш за данни за домейн на приложение, а само кеш за екземпляр на контекст.

Ако създадете нов контекст на заявка или заявка, започвате с празен кеш и EF ще извлече данните от базата данни.

Освен това терминът „кеш за екземпляр на контекст“ може да бъде подвеждащ, тъй като не означава, че EF няма да изпълнява заявки към базата данни, ако обектите вече са заредени в контекстния кеш. Начинът, по който работи този кеш и как можете да го използвате (или не) е следният:

  • Всяка заявка за LINQ-to-Entities на DbSet<T> или обикновено на IQueryable<T> ще изпълни заявка към база данни, без значение дали обектите вече съществуват в контекста или не. Но ако обект със същия ключ като запитван обект вече съществува в контекста, EF ще изхвърли резултата от това запитване и ще върне екземпляра на кеширания обект обратно на извикващия.

    Той прави тази проверка дали обектът със същия ключ съществува след като е изпълнил заявката. (За сложни заявки - например заявки, които съдържат Include - не може да направи тази проверка преди, защото не може да знае кои обекти и ключови стойности ще бъдат върнати.)

    Това е поведението по подразбиране (MergeOption е 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, ще получите различно поведение за сравнения на низове по отношение на чувствителността към главни и малки букви и т.н., и т.н.

person Slauma    schedule 11.06.2013
comment
Благодаря за чудесното обяснение. Досега бях напълно пропуснал факта, че може да се използва кеширана версия, дори ако се издават заявки към базата данни. Използвах SQL Server Profiler и видях заявки, които не върнаха свежи данни в приложението ми!? Най-накрая разбрах, че моят персонализиран MembershipProvider се поддържа от рамката между заявките, както и контекстът, който запазва. Друг код се изпълняваше в контексти и нещата се объркаха напълно. - person R. Schreurs; 02.07.2013