Entity framework отключить кэширование
The model for that context is then cached and is for all further instances of the context in the app domain. This caching can be disabled by setting the ModelCaching property on the given ModelBuidler, but note that this can seriously degrade performance.
Проблема в том, что построитель модели не содержит свойства с именем ModelCaching .
Как можно отключить кеширование модели (например, для изменения конфигурации модели во время выполнения)?
К сожалению нет. Я изменил свой подход к проекту, поэтому больше не нужно было исследовать эту проблему.
У меня такая же проблема: один контекст БД, 2 или более разных моделей БД (разные только по именам таблиц)
Мое решение для EF6: можно по-прежнему использовать внутреннее кеширование Entity Framework модели db, но проводить различие между DbModel (s) в том же DbContext, реализуя интерфейс IDbModelCacheKeyProvider в производном DbContext.
Implement this interface on your context to use custom logic to calculate the key used to lookup an already created model in the cache. This interface allows you to have a single context type that can be used with different models in the same AppDomain, or multiple context types that use the same model.
Надеюсь, это кому-то поможет.
Это прекрасно работает. Все, что вам нужно сделать, это вернуть разные ключи для каждого экземпляра модели.
@Kramii Я подозреваю, что в вашем подходе может быть предостережение, если мы используем случайный guid в качестве ключа: если базовый кеш безграничен (то есть он каким-то образом не ограничен, pe 1000 элементов или что-то в этом роде), то чем больше вы создаете db-context в течение жизненного цикла приложения, тем больше db-моделей кэшируется, и вы получаете утечку памяти. Просто предупреждение.
Возможно, старый EF4 Docu все еще находится в EF6. см. modelBuilder.CacheForContextType недоступен
См. Также DbContext Constructor для передачи модели DbContext Constructor
Я не пробовал, но теоретически можно каждый раз передавать модель.
Предварительное предупреждение: само собой разумеется, что показанный ниже механизм будет покрывать ваши потребности, если вам не нужно выполнять соединения между таблицами, которые поступают из разных контекстов. Если вам нужны такие операции, вам придется дополнительно усовершенствовать механизм, показанный ниже, с помощью небольшого API, чтобы вы могли динамически связывать указанные таблицы с некоторой строкой или числом (чтобы вы могли получить доступ и динамически комбинировать их соответствующие DBSet во время выполнения) . Выполнение такого рода вещей - хотя и в более общем плане - немного сложно и выходит за рамки этого ответа.
Вот полноценная реализация предложенного байрогом механизма - вся заслуга ему. Обратите внимание, что мы получаем соединение с базой данных через новый DbContext по причинам, описанным в комментариях:
Выглядит потрясающе! Если у вас сложная модель (много таблиц), как вы можете изменить Spawn выше? Можете ли вы добавить отрывок к приведенному выше примеру о том, как вызывающий абонент будет настраивать и использовать FooContext, скажем, если у вас есть несколько имен схем?
Я обновил реализацию, включив в нее пример (в комментариях), а также продемонстрировав, как можно сопоставить несколько таблиц. Надеюсь, это сработает для вас!
Примечание: гораздо быстрее кэшировать DbCompiledModel вместо DbModelBuilder. Как написано выше, .Build (). Compile выполняется много и очень дорого. Тем не менее, отличное решение.
@xDisruptor: я не видел, что вы подключаетесь к базе данных Oracle; SqlConnectionFactory действительно работает только для SqlServer.
Вот похожий вопрос
Единственный доступный подход исходит от менеджера программ группы Entity Framework ( Роуэн Миллер (MSFT) ):
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
Я пробовал следующий подход:
В результате я могу изменять параметры DbCompiledModel каждый раз, когда вызываю конструктор DbContext . Это все, что мне было нужно.
I see there are plenties of question on EF cache, but I have found no solution yet to my problem.
4 Answers 4
I have the same kind of issue: one db context, 2 or more different db models (different by table names, only)
My solution for EF6: One can still use the internal Entity Framework caching of db model but make a differentiation between DbModel(s) on the same DbContext by implementing IDbModelCacheKeyProvider Interface on derived DbContext.
Implement this interface on your context to use custom logic to calculate the key used to lookup an already created model in the cache. This interface allows you to have a single context type that can be used with different models in the same AppDomain, or multiple context types that use the same model.
Hope it helps someone.
@Kramii I suspect there might be a caveat in your approach if we use a random guid as key: If the underlying cache is boundless (that is to say it's not capped in some way, p.e. 1000 elements or something) then the more you spawn db-contexts during the application lifetime the more db-models get cached and you end up with a memory leak. Just a word of caution.
See also the DbContext Constructor to pass in a model DbContext Constructor
I haven't tried it, but theoretically you can pass in a model each time.
Forward Warning: It goes without saying that the mechanism shown below will cover your needs as long as you don't need to perform joins between tables that come from different contexts. If you need such operations then you will have to further refine the mechanism shown below with a small API so that you can dynamically associate said tables with some string or number (so that you may access and combine their respective DBSets dynamically at will in runtime). Doing this sort of thing -altough more general- is a bit complex and falls outside the scope of this answer.
Here's a full-blown implementation of the mechanism put forward by bairog - all credit goes to him. Notice that we get the connection to the database via new DbContext for reasons explained in the comments:
This looks awesome! If you have a complex model (lots of tables) how might you modify Spawn above? Can you add a snippet to your above example on how a caller would setup and use FooContext, say if you have multiple schema names?
I updated the implementation to include an example (in the comments) and to also show-case how multiple tables can be mapped. Hope it works for you!
@xDisruptor: I didn't see that you are connecting to a Oracle db; the SqlConnectionFactory indeed works only for SqlServer.
Here is similar question
The only available approach comes from the Program Manager of the Entity Framework team (Rowan Miller (MSFT)):
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
I've tried the following approach:
The result was that I can change parameters of DbCompiledModel every time I call DbContext constructor. That was all I needed.
С момента своего появления, наиболее важным классом Entity Framework являлся класс ObjectContext. Именно этот класс позволял взаимодействовать с базой данных используя сущностную модель классов. Класс контекста позволяет вам создавать и выполнять запросы, отслеживать изменения в объектах и отображать эти изменения на базу данных. Класс ObjectContext взаимодействует с другими важными классами платформы Entity Framework, например, с классом ObjectSet - его объекты можно использовать в качестве коллекций данных из таблиц, ObjectQuery – является ядром создания запроса и т.д.
Чтобы решить эту проблему, разработчики Entity Framework решили сделать более простой интерфейс для работы с данными, заключив в него все возможности ObjectContext, но при этом облегчив решение различных задач для работы с данными, для которых теперь вы можете использовать стандартные шаблоны. Новый набор классов был добавлен в версии Entity Framework 4.1 (EF 4.1). Главными классами новой упрощенной платформы являются DbContext, DbSet и DbQuery, а интерфейс для работы с этими новыми классами называют .
Новые классы контекста, как и старые, обеспечивают взаимодействие между сущностными классами модели и базой данных. Классы модели, в свою очередь, обеспечивают доступ к свойствам, настройкам отношений между таблицами и другим особенностям модели. Благодаря новым классам контекста и подходу Code-First, вы можете изменять структуру базы данных, добавлять, обновлять и удалять данные используя только код. Ниже описано назначение основных классов DbContext API:
DbContext
Является базовым классом Entity Framework и предоставляет широкие возможности по работе с базой данных: создание запросов, отслеживание изменений и сохранение данных в базе.
DbSet
Описывает набор сущностных классов, который затем можно использовать в коде для создания запросов CRUD (create, read, update, delete) к данным. С помощью экземпляров этого класса описываются различные объекты базы данных (таблицы, представления, хранимые процедуры и т.д.)
DbQuery
Обеспечивает возможность создания запросов, при этом взаимодействовать с этим классом напрямую вам не понадобится, благодаря использованию возможностей класса DbSet.
DbModelBuilder
Этот класс является связывателем модели – он создает связь между классами модели и схемой базы данных. DbContext позволяет взаимодействовать с этим классом благодаря методу OnModelCreating(), в котором вы можете внести настройки привязки модели, перед ее построением. Напомню, такой подход к настройке модели называют Fluent API.
Database
Предоставляет доступ к базе данных, лежащей в основе классов модели Entity Framework. Вы можете использовать методы этого класса для создания или удаления базы данных, проверки ее существования или выполнения произвольной команды SQL. Вы также можете использовать статические методы этого класса, чтобы удалить базу данных или проверить ее существование, используя строку подключения. Этот класс доступен в классе контекста через одноименное свойство Database.
DbExtensions
Этот класс определяет несколько полезных статических методов, с помощью которых можно настроить запросы, например, отключить кэширование для запросов.
Ранее мы уже рассмотрели как создается модель данных в подходе Code-First и рассмотрели настройки этой модели с использованием Fluent API и аннотаций данных. При использовании подходов Database-First и Model-First беспокоиться о настройке модели сущностных классов не нужно, т.к. она генерируется автоматически. При этом мы не рассмотрели работу с данными (как можно добавлять, изменять или удалять данные в таблицах базы данных).
Если вы знакомы с общими концепциями реляционных баз данных, то должны знать, что инструкции языка для работы с данными (такого, например, как T-SQL) разделяются на два вида: DDL (Data Description Language) – язык описания данных и DML (Data Manipulation Language) – язык изменения данных. Фактически, до сих пор, мы рассмотрели как использовать инструкции DDL в Entity Framework, в последующих статьях мы рассмотрим работу с данными DML в Entity Framework.
Итак, в предыдущих статьях мы описали практически всю функциональность, которую нужно знать при определении модели данных с Code-First. Теперь мы знаем какие соглашения использует Entity Framework при проектировании базы данных из классов модели, и как переопределять эти соглашения с использованием аннотаций данных и Fluent API. Тем не менее, Code-First также включает в себя некоторые более продвинутые функциональные возможности, которые вы можете использовать в своих приложениях. Далее мы рассмотрим некоторые из таких возможностей.
Использование ObjectContext вместо DbContext
Рекомендуемым классом контекста в современных приложениях Entity Framework является DbContext. Теме не менее, если вам необходимы продвинутые возможности ObjectContext через DbContext, вы можете реализовать в вашем классе контекста интерфейс IObjectContextAdapter, для доступа к свойствам и методам ObjectContext из DbContext. Также вы можете напрямую использовать ObjectContext в Code-First. Это бывает необходимо, если вы хотите применить подход Code-First для старого приложения, в котором написана куча методов доступа к данным на основе ObjectContext.
Подробно описывать здесь возможности ObjectContext мы не будем (для этого вы можете посетить статьи, ссылки на которые показаны выше), вместо этого давайте покажем как создать класс контекста с использованием ObjectContext, аналогичный тому, что мы использовали в примерах ранее с использованием DbContext (начиная с версии Entity Framework 4.1 класс ObjectContext был перенесен из основного пространства имен System.Data.Entity в пространство имен с классами ядра конфигурации EF System.Data.Entity.Core.Objects):
Обратите внимание, что здесь для установки объектов сущностей используется объект ObjectSet, а не DbSet, при этом эти объекты нужно автоматически зарегистрировать в конструкторе класса контекста с помощью метода CreateObjectSet.
Background
First, I have inherited an application made of a strange mixture of EF (model-first to define entities) and plain old SQL (to manipulate data). What I did was to refactor the application in order to:
- Make simple queries (like GetAll() for an entity) use EF6 LINQ
- Leave complex data manipulation in SQL, using DbContext.Database.Connection when needed
- Add Spring.Web support to enable DI and transactions (not yet)
At the current point, I have reorganized the code so that the main function of the application (running complex SQL queries on huge datasets) works as it did before, but then lookup domain entity manipulation is done smarter using as most Entity Framework as possible
As most.
One of the pages I inherited is a multi-checkbox page I'm going to show you for best understanding. I won't discuss the previous implementor's choice, because it's cheaper to fix my current problem and later refactor code than blocking development for a broken feature.
This is how the page looks like
Basically the Controller method is the following
Each string[] parameter is a column in the table. The ActivateFlagFor method runs two queries in sequence
Удаление соглашений
В предыдущих статьях мы видели, что Code-First следует некоторым соглашениям при проектировании базы данных из классов модели данных. Вы можете удалить одно или несколько соглашений из вашего приложения, используемых по умолчанию. Соглашения реализуется в виде классов, находящихся в пространстве имен System.Data.Entity.ModelConfiguration.Conventions. На рисунке ниже показан полный список соглашений, используемых в Code-First версии Entity Framework 6:
Например, вы можете удалить соглашение о каскадном удалении, при котором каскадное удаление автоматически добавляется при связи один-ко-многим. Для этого в Fluent API можно использовать метод Remove(), который вызывается на объекте ConvenctionsConfiguration, который доступен через свойство Conventions объекта DbModelBuilder. Ниже показан соответствующий пример:
Теперь при создании связи один-ко-многим каскадное удаление не будет использоваться автоматически, это позволяет сэкономить время, если в приложении нужно везде отключить это соглашение. Если вы захотите явно включить каскадное удаление при отключенном соглашении, вы можете использовать для этого средства Fluent API, о которых мы рассказывали в статье “Каскадное удаление данных”.
How I use the DbContext
Of course some of you may ask "how do you use your DbContext?" "do you dispose of it correctly?".
The model for that context is then cached and is for all further instances of the context in the app domain. This caching can be disabled by setting the ModelCaching property on the given ModelBuidler, but note that this can seriously degrade performance.
The problem is the model builder does not contain any property named ModelCaching.
How it is possible to disable the model caching (e.g. for changing model configuration in a run-time)?
Unfortunately not. I've changed my approach in the project so it wasn't needed to investigate this problem more.
The straight question is
How do I completely disable Entity Framework 6 cache? Or, can I programmatically tell EF to forget about the cache because something happened to data?
When the cache kicks in
The following is the behaviour:
- I first load the page issuing a LINQ select: checks match the ones and zeroes in columns
- I change one or more checks and submit
- The controller issues the queries to update checks in the DB
- Before redirecting (!means new request!) to reload the page, I check the DB and the changes are applied
- The page reloads issuing the same LINQ select above: old checks are displayed
I am sure that this is a caching problem, because reloading the application fixes the problem. Since the main feature of the application is totally SQL based, changes to lookup tables are reflected into main operation and that's the correct behaviour.
I understand that EF caching is a great feature for performance, but in my case I just don't want it, at least until I migrate the whole application to LINQ DML (probably impossible).
Управление кэшированием модели
Ранее вы видели, что Code-First заботится о многих вещах используя автоматические соглашения, но вы можете взять контроль над ними и изменить поведение, когда это необходимо. Кэширование модели не является исключением, хотя до этого раздела мы не говорили о том, что Code-First использует кэширование. На самом деле Code-First сохраняет в памяти процесса классы модели и примененные к ним конфигурации, так, что при повторном запуске приложения Code-First загружает кэшированную версию модели если она не изменилась.
Процесс создания модели включает в себя загрузку сущностных типов с помощью свойств DbSet класса контекста, применение к ним сначала автоматических соглашений, а затем настроек, которые вы указывали с помощью аннотаций данных и Fluent API. Этот процесс является довольно дорогостоящим в плане производительности, особенно если вы используете большую модель и применяете к ней сложные настройки. Чтобы избежать этих накладных расходов, Code-First использует кэширование после первого построения модели, а затем просто воссоздает модель из кэша приложения.
Отключить кэширование модели в настройках приложения вы не можете, но вы можете вручную построить модель используя метод DbModelBuilder.Build(). Получить доступ к объекту DbModelBuilder в коде приложения не так то просто. Для этого вы должны вручную создать этот объект, указав какие классы должны отображаться на таблицы базы данных, как показано в примере ниже:
Обратите внимание, что в методе Build() мы указываем тип поставщика данных. В нашем случае таким поставщиком будет SQL Server 2012.
Читайте также: