2014-04-03 3 views
0

Я использую EntityFramework 5 работает на .NET 4.5Как получить исходное значение из DbContext.Attach()?

Я пытаюсь выполнить обновление записи, используя подход, как показано ниже:

var rec = DbCntx.MyRecords.Attach(changedRecord); 
var entry = DbCntx.Entry(changedRecord); 
if (entry.State == EntityState.Modified) DbCntx.SaveChanges(); 

Переданный в объекте данных changedRecord содержал по меньшей мере, 1 значение поля изменено, сравнено с фактическим дБ. Однако элемент Entry.State всегда неизменен, поэтому SaveChanges() никогда не запускается.

Я пишу эту процедуру обновления для поддержки любых изменений данных в файле changedRecord, изменения данных полностью зависят от клиента/вызывающего, поэтому я не должен специально изменять значение поля в этой процедуре.

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

Без исходных данных я не могу определить, какие свойства являются изменениями. Если я попытаюсь использовать Find(), First/SingleOrDefault(), чтобы найти запись 1st, я не могу использовать Attach() позже, поскольку это вызовет ошибку «ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом».

от Googling, некоторые намекают на использование Detach(), но Detach недоступен в DbContext.

+0

Я нашел обходной путь, чтобы получить работу Detach: http://stackoverflow.com/questions/4168073/entity-framework-code-first- no-detach-method-on-dbcontext – Kelmen

ответ

0

Это, как правило, тот случай, когда вы хотите использовать AddOrUpdate (или this для версии 6):

using System.Data.Entity.Migrations; 
.... 

DbCntx.MyRecords.AddOrUpdate(changedRecord); 
DbCntx.SaveChanges(); 

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

+0

Я изучил этот метод, но это не соответствовало моей потребности. Единственное, что я могу сказать, это не ошибка EF, я могу добиться этого, просто изменив EntityState на Modified с использованием первоначального подхода. – Kelmen

+0

Ваша проблема: «Я не могу получить исходные значения данных». Вот что делает «AddOrUpdate» для вас. Конечно, вы можете пометить весь объект как измененный, но это сгенерирует инструкцию UPDATE, обновляющую * все * значения (включая неизменные значения). Если это нормально, вы можете оставить это таким образом. –

+0

Я выполнил фактический тест с помощью AddOrUpdate(), он обновляет поля только с разными значениями. Мне даже не нужно выполнять код для сравнения, в некотором роде он выполняет этот вопрос. Спасибо. Но на самом деле мне нужно зафиксировать различия в кодах для ведения журнала аудита. Во всяком случае, это правильный ответ на этот вопрос. Спасибо. – Kelmen

0

AddOrUpdate(), предложенный Гертом, сработал. Однако мне нужно зафиксировать различия в кодах. В конце концов, это то, что я разработал, используя DbPropertyValues:

  dbCntx.MyRec.Attach(chgRec); 

      var entry = dbCntx.Entry(chgRec); 

      var dbVals = entry.GetDatabaseValues(); 
      var dbValsPs = dbVals.PropertyNames; 

      foreach (var p in dbValsPs) 
      { 
       var ep = entry.Property(p); 
       var cv = ep.CurrentValue; 
       var dbv = dbVals.GetValue<object>(p); 

       if (!MyHelper.AreValuesEqual(cv, dbv)) 
        ep.IsModified = true; 
      } 

      if (entry.State == EntityState.Modified) 
       affectedCount = dbCntx.SaveChanges(); 

    public static bool AreValuesEqual<T>(T valueA, T valueB) 
    { 
     // array handling (such as byte[]) 
     if (valueA != null) 
     { 
      if (valueB == null) return false; 

      Type t = valueA.GetType(); 
      if (t.IsArray) 
      { 
       IEnumerable<object> listA = (valueA as Array).Cast<object>(); 
       IEnumerable<object> listB = (valueB as Array).Cast<object>(); 
       return listA.SequenceEqual(listB); 
      } 
     } 

     return EqualityComparer<T>.Default.Equals(valueA, valueB); 
Смежные вопросы