【问题标题】:Difference between Entity Framework's ConcurrencyCheck and standard TransactionScopes?实体框架的 ConcurrencyCheck 和标准 TransactionScopes 之间的区别?
【发布时间】:2013-09-15 16:52:27
【问题描述】:

我是管理并发的新手,如果这个问题消息不灵通,我深表歉意。

在过去的项目中,我通过将操作包装在 TransactionScope 中来实现并发检查 - 如下所示:

using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
    var copiedFolder = new Folder();
    using (var db = CreateContext())
    {
        // do stuff safely
    }
    scope.Complete();
    return copiedFolder;
}

但是我刚刚遇到了 Entity Framework 的并发方法:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

我想知道什么时候使用一个比另一个更好。从技术上讲,它们是一样的吗?如果不是,它们有何不同?

【问题讨论】:

    标签: c# entity-framework concurrency


    【解决方案1】:

    它们不是一回事。并发作为一种机制可以确保当两个用户同时访问同一个实体时不会进行覆盖。

    我给你举个例子。想象一下 ID 为 541 且 Name 设置为“Alex”的行。

    假设您有两个用户,用户 A 和用户 B,他们都试图修改该行的名称。以下场景是并发的全部内容:

    • 用户 A 从数据库中读取实体。
    • 用户 B 从数据库中读取实体。
    • 用户 A 将 Name 的值修改为“Alexander”并提交更改为 数据库。
    • 用户 B 将 Name 的值修改为“Alexander B”并提交更改为 数据库。

    用户 A 所做的更改在用户 B 不知情的情况下被覆盖。

    并发所做的基本上是确保如果用户 B 读取和用户 B 更改提交之间的值发生变化,它将抛出 DbConcurrencyException 指示实体已更改,从而为用户 B 提供取消保存或继续的能力无论如何。

    当您想确保特定属性不会被隐形覆盖时,您可以使用 [ConcurrencyCheck] 对其进行标记。默认情况下,实体框架通过在 WHERE 子句中提供 Id(身份)列来进行更新。当另一列标有 [ConcurrencyCheck] 时,它还将向 UPDATE 命令添加附加条件,在本示例中基本上是 WHERE NAME = 'Alex'。因此,由于 Alex 不再是数据库中的值(用户 A 已更改它),它将执行 0 次更新,这将在内部导致异常。

    【讨论】:

      【解决方案2】:

      从技术上讲,它们是一回事吗?

      不,他们不是。它们甚至没有必然的关系。

      • TransactionScope 用于确保在一个事务中提交数据库更改。当出于某种原因需要在一个数据库事务中发生多个 SaveChanges 调用时,通常将 TS 与 Entity Framework 一起使用。一个典型的场景是保存一个实体并将其生成的主键设置在另一个实体的某些属性中。 (请注意,一个SaveChanges 调用始终在一个事务中,通常不需要 TS)。

        TS 不解决任何并发冲突。当两个用户影响相同的记录时,最后提交事务的用户获胜。

      • 并发解析是关于当两个不同的用户尝试“同时”更改相同记录时该怎么做。您引用的链接详细说明了 EF 支持的最常见的策略,乐观并发。 EF 中最常见的方法是在数据库表中引入TimeStamp 列,该列(至少在 SQL 服务器中)在每次更新记录时自动递增。时间戳列也在概念模型(=类模型)中引入并标记为[Timestamp](数据注释)或IsConcurrencyToken(流畅映射),因此该属性将包含在更新和删除命令中。简而言之,它看起来像这样:

        UPDATE x SET y WHERE x.TimeStamp = <value when the record was fetched>
        

        当另一个用户同时更新记录时,EF 会记录零个受影响的记录并抛出DbUpdateConcurrencyException。您可以在 number of ways 中处理此异常。

      【讨论】:

        【解决方案3】:

        Timestamp 属性只能应用于单字节数组属性,而ConcurrencyCheck 属性可以应用于任何数据类型的任意数量的属性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-24
          • 1970-01-01
          • 2020-05-25
          • 2017-01-16
          • 2012-01-04
          • 2010-09-22
          相关资源
          最近更新 更多