【问题标题】:Entity Framework handling concurrency实体框架处理并发
【发布时间】:2012-12-10 13:43:10
【问题描述】:

场景:

我有多个帐户。每个帐户都有剩余信用。每个帐号对应多个用户。

我希望 RemainingCredit 字段正确反映剩余信用(我正在使用 EF 抽象出数据库)。

E.G. 在初始信用为 X 并且有 2 个用户登录的情况下,一个花费 A,一个花费 B ,我希望最终总和为 X-A-B(读取/修改/保存的顺序应该无关紧要)。

阅读后,我认为乐观并发处理是我正在寻找的,因为它可以很好地扩展,这对我的场景非常重要。 结束过程类似于:

ComputeRemainingCredit(Double amountToBeDeducted) {
    Account acc = context.Accounts.Where(condition)
    ComputeRemainingCreditInternal(acc, amountToBeDeducted);
}

ComputeRemainingCreditInternal(Account acc, Double amountToBeDeducted) {
try {
    acc.RemainingCredit = acc.RemainingCredit - amountToBeDeducted;
    context.SaveChanges();
}
catch (OptimisticConcurrencyException  ex) {
    context.Refresh(RefreshMode.StoreWinds, acc);
    //now I need to rerun the operation
    ComputeRemainingCreditInternal(acc, amountToBeDeducted);
}
}
  1. 这是对 EF 中乐观并发的正确解释/实现吗?
  2. 我的最终目标是更新 RemainingCredit 字段。有没有比 OptimisticConcurrencyException 更好的解决方案?

【问题讨论】:

  • 这是我见过的最糟糕的并发使用。这不是您在数据库上进行基本数学运算的方式。只需查询即可。
  • 想详细了解您的评论?如果我做错了——指出我做错了什么,这样我才能改进。只说我错了一点用都没有。
  • @mattmanser 你能否提供一个适合这种情况的 UPDATE 示例?

标签: c# entity-framework entity-framework-4 concurrency


【解决方案1】:

您需要在表中使用一个字段作为时间戳或版本号,并将其用于乐观并发检查。

假设您有一个Version 字段。将该字段的ConcurrencyMode 属性设置为Fixed,然后EF 将为您进行乐观并发检查,并在必要时抛出OptimisticConcurrencyException。

另一种方法是自己完成这项工作 - 获取当前记录,根据您正在更新的记录中的字段值验证字段值,相应地允许或禁止更新。

编辑另见http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx

编辑或多或少的伪代码:

bool mustRetry = true;
while (mustRetry)
{
    try
    {
        SpendTheMoney(context, parameters);
        mustRetry = false;
    } catch (OptimisticConcurrencyException exc)
    {
        // Do logging if you need, then just swallow the exception
    }
}

【讨论】:

  • 我知道我需要 Version/RowVersion/Timespamp 字段才能进行乐观并发检查。我的问题更多地涉及设计方法 - 具有重新输入功能来计算剩余金额 - 会这样做吗?其他选择?
  • 我想在SpendTheMoney() 函数中重新计算剩余信用是最简单的。
  • 吞下你的意思是异常 - 用最新数据调用 SpendTheMoney?
  • 通过吞下异常,我的意思是不重新抛出它。上面的while循环确保SpendTheMoney()在OptimisticConcurrencyException的情况下被再次调用。
  • 好吧 - 第一次尝试时错过了 while 循环。看起来类似于原始代码,使用一段时间而不是 callToSelf。谢谢你的例子。
【解决方案2】:

作为替代方案,您可以向用户显示一条错误消息,指出操作失败,因为数据已被修改,然后向他显示数据的当前状态。如果这是他/她的意图,用户将决定重试该操作。

你可以在这里找到一篇关于实体框架中并发的好文章:

Handling Concurrency with the Entity Framework in an ASP.NET MVC Application

【讨论】:

  • 我不能问用户,因为这是一个“幕后”操作——它应该“几乎总是”成功——只有当 RemainingCredit 低于一定数量时,我才必须发送“警告电子邮件” ”。我已经看过您指向的文章并阅读了它 - 我的案例是“不要把它留给用户”的场景
猜你喜欢
  • 1970-01-01
  • 2015-06-27
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 2013-03-07
  • 1970-01-01
  • 2010-10-02
相关资源
最近更新 更多