18

在处理多个潜在异常时,context.SaveChanges()其中一个异常是OptimisticConcurrency. 微软在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) 上,这似乎不起作用,因为在我的 EF5、代码优先、DbContext 派生类Refresh()中不存在。context

我确实看到context.Entry(context.SalesOrderHeaders).Reload();了-但这似乎是直接从数据库重新加载,而不是刷新/合并(策略客户端获胜)。

任何想法如何处理 EF5 中的乐观并发异常?实际上,即使是关于 SaveChanges() 中异常处理的一般指针也会很好

谢谢

4

2 回答 2

31

DbContext API中如何解决并发异常的方法是重新加载原始实体:

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));
于 2012-08-02T07:34:10.067 回答
1

如果您的更改仅针对一个实体(特别是一行,而不是其他表等),并发机制涵盖了您可以通过处理旧实体并创建新实体来刷新上下文。问题是当上下文被释放时,每个已更改且尚未提交的实体都会从上下文中分离出来,并且更改会丢失。所以要小心你单位工作的范围!

    catch (DbUpdateConcurrencyException)
    {
        context.Dispose();
        context = new DBContext();
        Entity entity = context.Set<Entity>().Find(entityFromOldContext.Id);

        entity.Property1 = entityFromOldContext.Property1;
        entity.Property2 += 4;

        context.commit();
    }

在实体中,我使用额外的属性来控制并发性,如下所示:

[Timestamp]
public Byte[] RowVersion { get; set; }

这可能不是优雅的方式(并且打破了 UnitOfWork 模式),但在某些情况下它可能很有用,最终可以替代上述帖子。

于 2013-05-08T17:54:37.487 回答