Отменить изменения в сущностных сущностях

это может быть тривиальным вопросом, но: Поскольку инфраструктура сущности ADO.NET автоматически отслеживает изменения (в сгенерированных сущностях) и поэтому сохраняет исходные значения, как я могу отменить изменения, внесенные в объекты сущности?

У меня есть форма, которая позволяет пользователю редактировать набор объектов «Клиент» в виде сетки.

Теперь у меня есть две кнопки «Принять» и «Восстановить»: если щелкнуть «Принять», я вызываю Context.SaveChanges() а измененные объекты записываются обратно в базу данных. Если щелкнуть «Revert», я бы хотел, чтобы все объекты получили свои исходные значения свойств. Каким будет код для этого?

благодаря

В EF нет операции отмены или отмены изменений. Каждый объект имеет ObjectStateEntry в ObjectStateManager . Запись состояния содержит исходные и фактические значения, поэтому вы можете использовать исходные значения для перезаписывания текущих значений, но вы должны делать это вручную для каждого объекта. Это не приведет к изменению свойств навигационных свойств / отношений.

Обычный способ «вернуть изменения» – это утилизировать контекст и перезагружать объекты. Если вы хотите избежать перезагрузки, вы должны создать клоны объектов и изменить эти клоны в контексте нового объекта. Если пользователь отменяет изменения, у вас все еще будут оригинальные объекты.

Query ChangeTracker из DbContext для грязных элементов. Устанавливать удаленные элементы можно без изменений и добавить элементы в отдельный. Для измененных элементов используйте исходные значения и задайте текущие значения записи. Окончательно установите состояние измененной записи в неизмененное:

 public void RollBack() { var context = DataContextFactory.GetDataContext(); var changedEntries = context.ChangeTracker.Entries() .Where(x => x.State != EntityState.Unchanged).ToList(); foreach (var entry in changedEntries) { switch(entry.State) { case EntityState.Modified: entry.CurrentValues.SetValues(entry.OriginalValues); entry.State = EntityState.Unchanged; break; case EntityState.Added: entry.State = EntityState.Detached; break; case EntityState.Deleted: entry.State = EntityState.Unchanged; break; } } } 
 dbContext.Entry(entity).Reload(); 

Подход к MSDN :

Перезагружает объект из базы данных, перезаписывая любые значения свойств со значениями из базы данных. После вызова этого метода объект будет находиться в состоянии Unchanged.

Обратите внимание, что возврат запроса к базе данных имеет некоторые недостатки:

  • сетевой трафик
  • Перегрузка БД
  • увеличенное время отклика приложения

Это сработало для меня:

 dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item); 

Где itemitem клиента, подлежащий возврату.

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

 public void Rollback() { dataContext.Dispose(); dataContext= new MyEntities(yourConnection); } 
 // Undo the changes of all entries. foreach (DbEntityEntry entry in context.ChangeTracker.Entries()) { switch (entry.State) { // Under the covers, changing the state of an entity from // Modified to Unchanged first sets the values of all // properties to the original values that were read from // the database when it was queried, and then marks the // entity as Unchanged. This will also reject changes to // FK relationships since the original value of the FK // will be restored. case EntityState.Modified: entry.State = EntityState.Unchanged; break; case EntityState.Added: entry.State = EntityState.Detached; break; // If the EntityState is the Deleted, reload the date from the database. case EntityState.Deleted: entry.Reload(); break; default: break; } } 

Это сработало для меня. Однако вы должны перезагрузить свои данные из контекста, чтобы принести старые данные. Источник здесь

«Это сработало для меня:

 dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item); 

Где item – это объект клиента, подлежащий возврату ».


Я провел тесты с ObjectContext.Refresh в SQL Azure, а «RefreshMode.StoreWins» запускает запрос к базе данных для каждого объекта и вызывает утечку производительности. На основе документации Microsoft ():

ClientWins: изменения свойств, сделанные объектами в контексте объекта, не заменяются значениями из источника данных. При следующем вызове SaveChanges эти изменения отправляются в источник данных.

StoreWins: изменения свойств, внесенные в объекты в контексте объекта, заменяются значениями из источника данных.

ClientWins не является хорошей идеей ни потому, что стрельба .SaveChanges будет совершать «отброшенные» изменения в источнике данных.

Я не знаю, что лучше всего, потому что избавление от контекста и создание нового вызвало исключение из сообщения: «Исходный провайдер потерпел неудачу при открытии», когда я пытаюсь запустить любой запрос в новом созданном контексте.

С уважением,

Henrique Clausing

Что касается меня, лучший способ сделать это – установить EntityState.Unchanged на все сущности, которые вы хотите отменить. Это гарантирует, что изменения возвращаются на FK и имеют более четкий синтаксис.

Я нашел, что это прекрасно работает в моем контексте:

Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);

Это пример того, о чем говорит Мннка. Следующий метод перезаписывает текущие значения сущности с исходными значениями и не вызывается firebase database. Мы делаем это, используя свойство OriginalValues ​​объекта DbEntityEntry и используем reflection для установки значений в общем виде. (Это работает с EntityFramework 5.0)

 ///  /// Undoes any pending updates ///  public void UndoUpdates( DbContext dbContext ) { //Get list of entities that are marked as modified List modifiedEntityList = dbContext.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified).ToList(); foreach( DbEntityEntry entity in modifiedEntityList ) { DbPropertyValues propertyValues = entity.OriginalValues; foreach (String propertyName in propertyValues.PropertyNames) { //Replace current values with original values PropertyInfo property = entity.Entity.GetType().GetProperty(propertyName); property.SetValue(entity.Entity, propertyValues[propertyName]); } } } 

Мы используем EF 4 с контекстом устаревшего объекта. Ни одно из вышеперечисленных решений прямо не ответило мне на это, хотя в конце концов я ответил на него, нажимая меня в правильном направлении.

Мы не можем просто распоряжаться и перестраивать контекст, потому что некоторые объекты, которые мы повесили в памяти (черт возьми, ленивая загрузка!), Все еще привязаны к контексту, но у них есть дети, которые еще не загружены. Для этих случаев нам нужно вернуть все исходные значения без забивания базы данных и не отбрасывая существующее соединение.

Ниже приведено наше решение по этой же проблеме:

  public static void UndoAllChanges(OurEntities ctx) { foreach (ObjectStateEntry entry in ctx.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached)) { if (entry.State != EntityState.Unchanged) { ctx.Refresh(RefreshMode.StoreWins, entry.Entity); } } } 

Надеюсь, это поможет другим.

Некоторые хорошие идеи выше, я решил реализовать ICloneable, а затем простой метод расширения.

Найдено здесь: Как клонировать общий список в C #?

Используется как:

 ReceiptHandler.ApplyDiscountToAllItemsOnReciept(LocalProductsOnReciept.Clone(), selectedDisc); 

Таким образом, я смог клонировать список моих продуктов, применять скидку к каждому элементу и не беспокоиться о возврате каких-либо изменений в исходном объекте. Не нужно разговаривать с DBContext и запрашивать обновление или работу с ChangeTracker. Вы можете сказать, что я не полностью использую EF6, но это очень хорошая и простая реализация и позволяет избежать ударов БД. Я не могу сказать, имеет ли это успех.

Interesting Posts

Есть ли способ настроить командную строку командной строки Windows?

Что предоставляет “ и где он документирован?

Как сохранить пользовательские объекты в NSUserDefaults

Сколько информации могут получить веб-сайты о вашем браузере / ПК?

DatatypeContexts Устарела в последнем GHC: Почему?

Как забронировать номер, но не настроить мой календарь как занятый

Центрирование элементов управления в форме в .NET (Winforms)?

Завершение процесса в unix вместо его прерывания

TypeError: не может использовать строковый шаблон для байтового объекта в re.findall ()

Можно ли прекратить выполнение R-кода внутри блестящего (без остановки блестящего процесса)?

Excel: условное форматирование (выделение) значений на основе другого рабочего листа

Как получить идентификатор элемента, нажатого с помощью jQuery

Каков наилучший способ автоматического обновления приложения Windows?

SimpleCursorTreeAdapter и CursorLoader для ExpandableListView

Какие выражения дают ссылочный тип, когда к ним применяется метод decltype?

Давайте будем гением компьютера.