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

Объект 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() были бы хороши

Спасибо

4b9b3361

Ответ 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), но он может быть полезен в некоторых ситуациях и, наконец, альтернатива вышеупомянутым сообщениям.