在Entity Framework中处理并发性问题

4

我正在寻找在使用Entity Framework时处理并发的最佳方式。最简单和最推荐的(也是在stack上)解决方案在这里描述: http://msdn.microsoft.com/zh-cn/library/bb399228.aspx 看起来像这样:

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");
}

但这样就够了吗?如果在 Refresh() 和第二个 SaveChanges() 之间发生了变化,会出现未捕获的 OptimisticConcurrencyException 吗?

编辑2:

我认为这将是最终解决方案:

    int savesCounter = 100;
    Boolean saveSuccess = false;
    while (!saveSuccess && savesCounter > 0)
    {
        savesCounter--;
        try
        {
            // Try to save changes, which may cause a conflict.
            int num = context.SaveChanges();
            saveSuccess = true;
            Console.WriteLine("Save success. " + num.ToString() + " updates saved.");
        }
        catch (OptimisticConcurrencyException)
        {
            // Resolve the concurrency conflict by refreshing the 
            // object context before re-saving changes. 
            Console.WriteLine("OptimisticConcurrencyException, refreshing context.");
            context.Refresh(RefreshMode.ClientWins, orders);

        }
    }

我不确定我是否理解Refresh()的工作原理。它是刷新整个上下文吗?如果是,为什么需要附加参数(实体对象)?还是说它只刷新指定的对象? 例如,在这种情况下,Refresh()的第二个参数应该传递什么:

Order dbOrder = dbContext.Orders.Where(x => x.ID == orderID);
dbOrder.Name = "new name";
//here whole the code written above to save changes

它应该是dbOrder吗?


2
+1 这正是我第一次阅读时对这个示例提出的同样的反对意见!通常在异常处理程序中执行“冒险”的操作(saveChanges)是不好的做法。看到这在官方文档中出现,我感到很惊讶。 - Gert Arnold
1
关于你的更改,看起来不错。我会小心地加入一种方式来中断循环,如果尝试100次仍无法解决问题的话。调试那些陷入无限循环的问题总是很困难的,虽然它们本应该永远不会发生;-) - Joachim Isaksson
1
尝试使用此链接中的方法,它使用一种不同的处理并发的方式,可能是更可靠的方法:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application - John John
1个回答

4

是的,即使第二次保存可能会导致乐观并发异常,如果在Refresh()SaveChanges()之间发生了更改,就像你所说的那样。

给出的示例只是一个非常简单的重试逻辑,如果您需要重试超过一次或以更复杂的方式解决冲突,最好创建一个循环,该循环将重试n次,而不是嵌套try/catch超过这个单一级别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接