新 ASP.NET MVC 6 标识中 AspNetUsers table 中的 ConcurrencyStamp 列的用途是什么?

What is the purpose of the ConcurrencyStamp column in the AspNetUsers table in the new ASP.NET MVC 6 identity?

新的 ASP.NET MVC 6 标识中 AspNetUsers table 中的 ConcurrencyStamp 列的用途是什么?

这是 AspNetUsers table 的数据库模式:

它也在 AspNetRoles table:

我记得它不存在于 ASP.NET MVC 5 标识中。

到目前为止我注意到它似乎具有 GUID 值,因为它是用以下代码定义的:

/// <summary>
/// A random value that must change whenever a user is persisted to the store
/// </summary>
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

但是这个文档不足以让我了解它在哪些情况下使用。

From the source code itself

    /// <summary>
    /// A random value that should change whenever a role is persisted to the store
    /// </summary>
    public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

基本上,见其名。用于标识数据当前版本的标记。如果您更改它,邮票也会更改。

所以如果两个并发更新同时进来,它们必须有相同的标记,否则其中一个应该被丢弃。

因此得名 ConcurrencyStamp

跟进 Maxime 的回复:

如果您查看 OnModelCreating() 方法中 IdentityDbContext 的实现,您会发现:

builder.Entity<TUser>(b =>
{
....
    b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
....

并且在 UserStore.UpdateAsync(...)-方法中:

    Context.Update(user);
    try
    {
        await SaveChanges(cancellationToken);
    }
    catch (DbUpdateConcurrencyException)
    {
        return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
    }

因此,它确实做了它应该做的事情:防止对用户对象进行并发更新。该令牌仅在 ASP 身份 EntityFramework 模块中使用 "under the hood"。基本上,如果发生一个用户对象的并发更新,数据库上下文会抛出 DbUpdateConcurrencyException。

作为名称状态,用于防止并发更新冲突。

例如,数据库中有一个叫UserA的Peter 2 管理员打开 UserA 的编辑器页面,想要更新此用户。

  1. Admin_1打开页面,看到用户叫Peter。
  2. Admin_2 打开页面,看到用户叫 Peter(很明显)。
  3. Admin_1 将用户名更新为 Tom,并保存数据。现在 UserA 在名为 Tom 的数据库中。
  4. Admin_2更新用户名为Thomas,并尝试保存。

如果没有 ConcurrencyStamp 会发生什么,Admin_1 的更新将被 Admin_2 的更新覆盖。 但是由于我们有 ConcurrencyStamp,当 Admin_1/Admin_2 加载页面时,就会加载图章。更新数据时,此戳记也会更改。 所以现在第 5 步将是系统抛出异常,告诉 Admin_2 该用户已经更新,因为他 ConcurrencyStamp 与他加载的不同。

认识到这实际上是一个 数据层特征 也很重要。 Identity defines the column as being a concurrency column 的架构,但实际上并未使用它。

Identity 代码库内部没有任何逻辑 - 只有当 EFCore 真正去保存它时它才会启动。

https://docs.microsoft.com/en-us/ef/core/modeling/concurrency

EF Code First - IsConcurrencyToken()