Аннулирование / отключение кэша Entity Framework
я вижу, что есть множество вопросов о кэше EF, но я еще не нашел решения своей проблемы.
прямой вопрос
как полностью отключить кэш Entity Framework 6? Или я могу программно сказать EF забыть о кэше, потому что что-то случилось с данными?
фон
во-первых, у меня есть унаследовала приложение, сделанное из странной смеси EF (model-first для определения сущностей) и простой старый SQL (для управления данными). То, что я сделал, это рефакторинг приложения для того, чтобы:
- сделать простые запросы (например,
GetAll()
для сущности) используйте EF6 LINQ - оставьте сложные манипуляции с данными в SQL, используя
DbContext.Database.Connection
при необходимости - добавить
Spring.Web
поддержка включения DI и транзакций (еще нет)
в текущий момент я реорганизовал код так, чтобы основная функция приложения (запуск сложного SQL запросы к огромным наборам данных) работает так же, как и раньше, но затем поиск доменных сущностей выполняется умнее, используя а всего Entity Framework, насколько это возможно
как большинство....
одна из страниц, которые я унаследовал,-это страница с несколькими флажками, которую я собираюсь показать вам для лучшего понимания. Я не буду обсуждать выбор предыдущего реализатора, потому что дешевле исправить мою текущую проблему и более поздний код рефакторинга, чем блокировать разработку для сломанного особенность.
вот как выглядит страница
в основном Controller
метод следующий
[HttpPost]
public ActionResult Index(string[] codice, string[] flagpf, string[] flagpg, string[] flagammbce, string[] flagammdiv, string[] flagammest,
string[] flagintab, string[] flagfinanz, string[] flagita, string[] flagest, string pNew){
Sottogruppo2015Manager.ActivateFlagFor("pf", flagpf);
Sottogruppo2015Manager.ActivateFlagFor("pg", flagpg);
Sottogruppo2015Manager.ActivateFlagFor("ammbce", flagammbce);
Sottogruppo2015Manager.ActivateFlagFor("ammdiv", flagammdiv);
Sottogruppo2015Manager.ActivateFlagFor("ammest", flagammest);
Sottogruppo2015Manager.ActivateFlagFor("intab", flagintab);
Sottogruppo2015Manager.ActivateFlagFor("finanz", flagfinanz);
Sottogruppo2015Manager.ActivateFlagFor("ita", flagita);
Sottogruppo2015Manager.ActivateFlagFor("est", flagest);
return RedirectToAction("Index", new { pNew });
}
каждого string[]
параметр представляет собой столбец в таблице. The ActivateFlagFor
метод выполняет два запроса в последовательности
UPDATE table SET --param1-- = 0;
UPDATE table SET --param1-- = 1 where id in (--param2--)
когда кэш срабатывает
следующее поведение:
- я сначала загружаю страницу, выдающую LINQ select: проверки совпадают с единицами и нулями в колонки
- я меняю один или несколько чеков и отправляю
- контроллер выдает запросы на обновление проверок в DB
- до перенаправления (!значит новый запрос!) чтобы перезагрузить страницу, Я проверяю БД и изменения применяются
- страница перезагружается, выдавая тот же LINQ select выше:отображаются старые чеки
я уверен, что это проблема кэширования, потому что перегруз приложение устраняет проблему. Поскольку основная функция приложения полностью основана на SQL, изменения в таблицах поиска отражаются в основной операции, и это правильное поведение.
я понимаю, что кэширование EF-отличная функция для производительности, но в моем случае я просто не хочу этого, по крайней мере, пока я не перенесу все приложение на LINQ DML (вероятно, невозможно).
как я использую DbContext
конечно, некоторые из вас могут спросить: "как вы использовать DbContext можно?- вы правильно распорядились?".
- я еще не интегрировал весенние транзакции в мои классы менеджера
- каждый объект, который выполняет действия на базе
I<Entity>Manager
расширенияBaseManager
-
DbContext
является объектом Spring с областью запросов. Я уже спросил о размещении объектов с областью запроса но в настоящее время я реализовал обходной путь, который, хотя и плохой,правильно распоряжается из DbContext в конце запроса.
пример кода
public class ExampleManagerImpl : BaseManager, IExampleManager
{
public void ActivateFlagFor(string aFlag, string[] aList)
{
string sql = "UPDATE table SET flag" + aFlag + " = 0";
RunStatementV1(sql);
if (aList != null && aList.Any())
{
sql = "UPDATE table SET flag" + aFlag + " = 1 WHERE id in (" + aList.ToCsvApex() + ")";
RunStatementV1(sql);
}
}
public IList<Models.Example> GetAll()
{
return DataContext.example.ToList(); //I don't dispose of the DataContext willingly
}
}
и
public abstract class BaseManager {
public DbContext DataContext { get; set; } //Autowired
protected void RunStatementV1(string aSqlStatement)
{
IDbConnection connection = DataContext.Database.Connection;
if (connection.State == ConnectionState.Closed || connection.State == ConnectionState.Broken) connection.Open(); //Needed because sometimes I found the connection closed, even if I don't dispose of it
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = aSqlStatement;
command.ExecuteNonQuery();
}
}
}
что я пробовал
- как остановить кэширование entity framework : отключение отложенной загрузки не работает
-
https://stackoverflow.com/a/22818783/471213:
Detach
кажется, решает проблему, но мне нужно применить ее к дюжине объектов, чтобы вернуться когда-нибудь в будущее
2 ответов
если вы хотите полностью игнорировать кэш EF6 для извлечения данных, добавьте AsNoTracking()
до конца вашего запроса (перед вызовом ToList()
или делать что-либо еще, что бы выполнить запрос.
обратите внимание, что это не будет проверять кэш для существующих данных, а также не будет добавлять результаты вызова базы данных в кэш. Кроме того Entity Framework не будет автоматически обнаруживать изменения сущностей, которые вы получить из базы данных. Если вы хотите изменить какие-либо объекты и сохранить их обратно в базу данных, перед вызовом SaveChanges()
.
ваш метод в настоящее время:
public IList<Models.Example> GetAll()
{
return DataContext.example.ToList();
}
это изменится на:
public IList<Models.Example> GetAll()
{
return DataContext.example.AsNoTracking().ToList();
}
если вас интересуют другие варианты работы с кэшем EF, я написал сообщение в блоге о переборе кэша EF6.
У меня тоже была эта проблема, но я мог ее исправить.
Я использую шаблон репозитория и использую DI по умолчанию .Net Core. Я использую AddSingleton(...), но это неправильно использовать с DbContext.
Итак, я изменился на AddScoped, как я читал из docs:службы с областью действия создаются один раз для каждого запроса.
это решило мою проблему.
вы должны прочитать этот раздел из ms docs: срок службы и регистрация Опции