【问题标题】:Concurrency with Entity Framework & SQL (ADO.NET)与实体框架和 SQL (ADO.NET) 的并发性
【发布时间】:2013-08-13 19:31:25
【问题描述】:

我遇到了一些并发问题。我阅读了http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx中的乐观并发处理

我有一段代码可以在我的 WCF 服务中进行实际测试:

    public GameResult PurchaseGameItem(int itemId)
    {
        using (var entities = new GameEntities())
        {
            var p1 = entities.Items.Where(p => p.ID == itemId).FirstOrDefault();
            p1.Coins = 1;

            using (var e2 = new GameEntities())
            {
                var p2 = e2.Items.Where(p => p.ID == itemId).FirstOrDefault();
                p2.Coins = 2;
                e2.SaveChanges();
            }

            entities.SaveChanges();
        }

        return GameResult.Success;
    }

此外,我已将模型中的“硬币”并发模式设置为“固定”。但是,这通过并且保存在数据库中的值是“1”。我已经尝试了几组值,所以这并不是“偶然正确”。为什么这里没有引发 OptimisticConcurrencyException?

[update #1]通过尝试下面的第一个响应并将它们组合起来,我设法有时获得了 DbUpdateConcurrencyException。它仍然不是我期待的 OptimisticConcurrencyException,但它是一些东西。基本上我不知道为什么它不会一直发生。

            var p1 = entities.Items.Where(p => p.ID == itemId).FirstOrDefault();
            var p3 = entities.Items.Where(p => p.ID == itemId).FirstOrDefault();

            p1.CoinValue = 14;
            p3.CoinValue = 115;

            using (var e2 = new GameEntities())
            {
                var p2 = e2.Items.Where(p => p.ID == itemId).FirstOrDefault();
                p2.CoinValue = 72;
                e2.SaveChanges();
            }

            entities.SaveChanges(); // This throws DbUpdateConcurrencyException, perhaps 50% of the time.

看起来这里存在并发问题! :D

[更新 #2] 好吧,我现在想出了其中的一部分,这主要是愚蠢的用户错误。 DbUpdateConcurrencyException 自第二次以来仅抛出一次,第二个子句会将其更新为它已经存在的值,因此该部分是合乎逻辑的。如果从同一个上下文中获取了两个实体,则将简单地考虑后一个更改,因此在第一个响应建议的“一个数据库连接”情况下,不会引发并发异常。这是合乎逻辑的,因为程序员可以不通过多个句柄访问对象。

我不明白的是 DbUpdateConcurrencyException 和 OptimisticConcurrencyException 之间的区别。我无法提高后者。

【问题讨论】:

    标签: c# entity-framework exception concurrency optimistic-concurrency


    【解决方案1】:

    我想知道你为什么要创建 2 个到数据库的连接?!

    public GameResult PurchaseGameItem(int itemId)
    {
        using (var entities = new GameEntities())
        {
            var p1 = entities.Items.Where(p => p.ID == itemId).FirstOrDefault();
            var p2 = entities.Items.Where(p => p.ID == itemId).FirstOrDefault();
    
            p1.Coins = 1;
            p2.Coins = 2;
    
            entities.SaveChanges();
        }
    
        return GameResult.Success;
    }
    

    【讨论】:

    • 我背后的逻辑只是模拟一个更现实的并发问题发生的场景。它不打算作为任何实际的、功能性的代码。话虽如此,您的方法会产生相同的结果。没有错误。
    • 哦,正如我在更新中提到的,这不会引发任何错误。您只是在相同的上下文中获得对同一个对象的两个引用,这不是问题(除非我误解了整个事情的工作原理)。
    • 是的,您需要两个到 DBContext 的连接,它们在同一时间更改相同的记录数据库,而不是您将得到 ConcurrencyException。
    【解决方案2】:

    OptimisticConcurrencyException 来自 ADO.NET,它是 ADO.NET 实体框架的基础。 DbUpdateConcurrencyException 由实体框架生成。如果不通过连接/命令对象直接使用 ADO.NET,则在使用 Entity Framework 时不应遇到 OptimisticConcurrencyException。

    【讨论】:

      猜你喜欢
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多