Объект framework 5.0 оптимизирует оптимизацию concurrency?
При обработке нескольких потенциальных исключений во время context.SaveChanges()
одно из исключений - OptimisticConcurrency
. Документация Microsoft по этому вопросу в http://msdn.microsoft.com/en-us/library/bb399228.aspx обсуждает это для EF 4.x...
try
{
// Try to save changes, which may cause a conflict.
int num = context.SaveChanges();
Console.WriteLine("No conflicts. " +
num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
// Resolve the concurrency conflict by refreshing the
// object context before re-saving changes.
context.Refresh(RefreshMode.ClientWins, orders);
// Save changes.
context.SaveChanges();
Console.WriteLine("OptimisticConcurrencyException "
+ "handled and changes saved");
}
... но в EF 5.0 (RC) это не работает, потому что Refresh()
не существует в моем EF5, в коде, в основе DbContext context
.
Я вижу context.Entry(context.SalesOrderHeaders).Reload();
- но это похоже на перезагрузку-из-db, а не обновление/слияние (с выигрышами в политическом клиенте).
Любые идеи, как обрабатывать оптимистичные исключения concurrency в EF5? Фактически даже общие указатели на обработку исключений в SaveChanges() были бы хороши
Спасибо
Ответы
Ответ 1
Способ устранения исключения concurrency в API DbContext перезагружает исходный объект:
catch (DbUpdateConcurrencyException ex)
{
// Get failed entry
var entry = ex.Entries.Single(...);
// Overwrite original values with values from database but don't
// touch current values where changes are held
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
}
Вы также должны иметь возможность использовать указанный код, но вы должны получить экземпляр ObjectContext
из вашего экземпляра DbContext
(это всего лишь оболочка вокруг ObjectContext
).
catch (DbUpdateConcurrencyException ex)
{
var objContext = ((IObjectContextAdapter)context).ObjectContext;
// Get failed entry
var entry = ex.Entries.Single(...);
// Now call refresh on ObjectContext
objContext.Refresh(RefreshMode.ClientWins, entry.Entity);
}
Вы даже можете попробовать:
objContext.Refresh(RefreshMode.ClientWins, ex.Entries.Select(e => e.Entity));
Ответ 2
Если ваши изменения относятся только к одному объекту (определенная одна строка, а не другие таблицы и т.д.), который покрывается механизмом concurrency, вам разрешается обновлять контекст, удаляя старый и создавая новый.
Дело в том, что контекст размещается в каждом измененном объекте и еще не зафиксирован, отделен от контекста, и изменения теряются. Поэтому будьте осторожны в отношении объема работы вашего устройства!
catch (DbUpdateConcurrencyException)
{
context.Dispose();
context = new DBContext();
Entity entity = context.Set<Entity>().Find(entityFromOldContext.Id);
entity.Property1 = entityFromOldContext.Property1;
entity.Property2 += 4;
context.commit();
}
В объекте я использую дополнительное свойство для управления concurrency следующим образом:
[Timestamp]
public Byte[] RowVersion { get; set; }
Возможно, это не элегантный способ (и разбивает шаблон UnitOfWork), но он может быть полезен в некоторых ситуациях и, наконец, альтернатива вышеупомянутым сообщениям.