Проблема кэширования платформы Entity Framework
Я новичок в Entity Framework.
Я получил некоторые значения в моей базе данных, используя EF. Возвращает отлично, а значения отображаются в метках. Но когда я удаляю все значения в моей таблице (без использования EF), запрос EF возвращает мои старые значения. Я знаю, что EF хранит значения в кэше и возвращает кэшированные данные для последующих запусков. Это правильно?
Итак, как я могу решить проблему, когда я удалил все значения в моей базе данных, но EF возвращает старые значения?
Редактировать:
Теперь я использовал datamodel.SaveChanges()
. Но теперь и он возвращает те же старые значения.
Мой пример запроса выглядит следующим образом:
SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.SaveChanges();
List<Compliance> compliance=new List<Compliance>();
IList<ComplianceModel> complianceModel;
if (HttpContext.Current.User.IsInRole("SuperAdmin"))
{
compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
}
Ответы
Ответ 1
Если вы знаете, что изменения произошли за пределами EF и хотите обновить ваш ctxt для определенного объекта, вы можете вызвать ObjectContext.Refresh
datamodel.Refresh(RefreshMode.StoreWins, orders);
Если это похоже на то, что это будет обычным явлением, вы должны отключить кэширование объектов в своих запросах:
SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.tblCities.MergeOption = MergeOption.NoTracking;
или для отключения кэширования уровня объектов для определенного объекта,
Context.Set<Compliances>().AsNoTracking();
Ответ 2
Когда вы используете EF, он по умолчанию загружает каждый объект только один раз для каждого контекста. Первый запрос создает объект instace и сохраняет его внутри. Любые последующий запрос, для которого требуется сущность с тем же ключом, возвращает это хранимый экземпляр. Если значения в хранилище данных изменились, вы все равно получаете объект со значениями из исходного запроса
Тщательный ответ:
fooobar.com/questions/11962/...
Ответ 3
EF не будет загружать изменения, если вы не запросите контекст. EF запросы db и загружает карты в объекты, он отслеживает изменения, которые вы выполняете на объектах, а не в базе данных. EF не отслеживает изменения, внесенные непосредственно в базу данных, и он никогда не будет отслеживать.
Вы загрузили List, этот список - ваш кеш в памяти. Даже вызов Save Changes не будет обновляться. Вам нужно будет снова запросить контекст, то есть создать новый список.
Чтобы увидеть изменения, вам нужно будет выполнить следующую строку еще раз,
datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList()
Ответ 4
Я думаю, вам следует следовать другим решениям здесь, но похоже, что вы хотите очистить кеш. Вы можете добиться этого, выполнив следующие действия:
var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30)
datamodel.Compliances.Local.ToList().ForEach(c => {
datamodel.Entry(c).State = EntityState.Detached;
});
count = datamodel.Compliances.Local.Count; // 0
Ответ 5
Ниже код помог моему объекту обновиться со свежими значениями базы данных. Команда Entry (object).Reload() заставляет объект вызывать значения базы данных
GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();
Ответ 6
Я рекомендую вам использовать некоторый MergeOption для всех EntitieSet после создания контекста, например:
var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>));
foreach (PropertyInfo objSetProp in objSetProps)
{
ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null);
objSet.MergeOption = MergeOption.PreserveChanges;
}
Читайте о MergeOption здесь: http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx
Думаю, вы будете использовать NoTracking.
Но вы хотите, чтобы очистили "кэшированные" объекты, отделив их.
var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
foreach (var objectStateEntry in entidades)
Ctx.Detach(objectStateEntry.Entity);
Где Ctx - мой контекст.
Ответ 7
Во-первых, я бы не предложил модифицировать базу данных, внешнюю по отношению к вашей системе, если только вы не выполняете тестирование и разработку.
EF DbContext содержит интерфейс IDisposable. Чтобы освободить любые кэшированные данные, сделайте вызовы Dispose вручную или поместите объект базы данных в блок использования.
using (SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities())
{
List<Compliance> compliance = new List<Compliance>();
IList<ComplianceModel> complianceModel;
if (HttpContext.Current.User.IsInRole("SuperAdmin"))
{
compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
}
}
Это позволит убедиться, что контекст очищается и воссоздается при следующем использовании. Обязательно сделайте это для всех своих вызовов, а не только из тех, с которыми у вас возникают проблемы.
Ответ 8
Я подозреваю, что основная проблема заключается в том, что ваш DbContext
слишком долго висит. Я могу сказать, что вы используете HttpContext
, что у вас есть веб-приложение, и Общие рекомендации при работе с DbContext включают
При работе с веб-приложениями используйте экземпляр контекста за запрос.
Если вы используете MVC, вы можете использовать шаблон Dispose в своем контроллере следующим образом:
public class EmployeeController : Controller
{
private EmployeeContext _context;
public EmployeeController()
{
_context = new EmployeeContext();
}
public ActionResult Index()
{
return View(_context.Employees.ToList());
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
base.Dispose(disposing);
}
}
Но вы действительно должны смотреть на инъекцию зависимостей управлять временем жизни DbContext
Ответ 9
Я думаю, что вам нужно GetDatabaseValues()
. Он используется как:
context.Entry(/*your entry*/).GetDatabaseValues();
Ниже приведена информация msdn:
Текущие значения - это значения, которые свойства объекта в настоящее время содержат. Первоначальные значения - это значения, которые были прочитаны из базы данных, когда объект был запрошен. Значения базы данных значения, которые в настоящее время хранятся в базе данных. Получение значения базы данных полезны, когда значения в базе данных могут иметь изменено с момента запроса объекта, например, когда одновременное редактирование база данных была сделана другим пользователем.
Ответ 10
Пара вещей, которые вы можете сделать.
- Используйте новый контекст. Кэшированные объекты хранятся в контексте. Использование нового контекста не позволяет использовать кеш.
- Если вам действительно нужен глобальный/долгосрочный контекст, у вас есть два дополнительных параметра:
a.) всегда вызывают метод Reload. db.Entry(entity).Reload()... это заставляет контекст перезагружать этот объект.
б) использовать объект SqlDependency для обнаружения, когда записи изменяются и перезагружают объекты по мере необходимости. https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3
Ответ 11
В моем случае это была плохая строка подключения. Сущность выглядела так, как будто у нее все хорошо, потому что она никогда не жаловалась, пока я не сделал контекст локальным, и, наконец, дал мне сообщение об ошибке.
Ответ 12
EF работает по-другому с методом find, который выдает данные из контекста. Остальные запросы выполняются из db. Если объект уже находится в контексте, возвращается существующий объект (текущие и исходные значения свойств объекта в записи не перезаписываются значения базы данных). Запрос выполняется к базе данных, когда:
Ссылка Microsoft
Он перечисляется оператором foreach (С#) или For Each (Visual Basic). Он перечисляется операцией коллекции, такой как ToArray, ToDictionary или ToList. Операторы LINQ, такие как First или Any, указываются в самой внешней части запроса. Вызываются следующие методы: метод расширения Load для DbSet, DbEntityEntry.Reload и Database.ExecuteSqlCommand. Когда результаты возвращаются из базы данных, объекты, которые не существуют в контексте, присоединяются к контексту. Если объект уже находится в контексте, возвращается существующий объект (текущие и исходные значения свойств объекта в записи не перезаписываются значениями базы данных).
При выполнении запроса сущности, которые были добавлены в контекст, но еще не сохранены в базе данных, не возвращаются как часть набора результатов. Чтобы получить данные, которые находятся в контексте, см. Локальные данные.
Если запрос не возвращает строк из базы данных, результатом будет пустая коллекция, а не ноль.