Подтвердить что ты не робот

Проблема кэширования платформы 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();
}
4b9b3361

Ответ 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. Когда результаты возвращаются из базы данных, объекты, которые не существуют в контексте, присоединяются к контексту. Если объект уже находится в контексте, возвращается существующий объект (текущие и исходные значения свойств объекта в записи не перезаписываются значениями базы данных).

При выполнении запроса сущности, которые были добавлены в контекст, но еще не сохранены в базе данных, не возвращаются как часть набора результатов. Чтобы получить данные, которые находятся в контексте, см. Локальные данные.

Если запрос не возвращает строк из базы данных, результатом будет пустая коллекция, а не ноль.