2

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

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

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

但是我刚刚遇到了实体框架的并发方法:http ://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework -in-an-asp-net-mvc-应用程序

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

4

3 回答 3

4

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

我给你举个例子。想象一下 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 次更新,这将在内部导致异常。

于 2013-09-15T19:08:45.073 回答
2

从技术上讲,它们是一样的吗?

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

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

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

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

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

    同时,当另一个用户更新记录时,EF 会记录零个受影响的记录并抛出DbUpdateConcurrencyException. 您可以通过多种方式处理此异常。

于 2013-09-15T21:25:43.353 回答
2

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

于 2018-10-28T18:45:47.233 回答