You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用EF Core与Visual Studio的Razor Pages应用并发冲突未被识别

并发冲突检测失效问题修复

问题描述

按照ASP.NET Core EF RP并发实现指南调整代码后,并发冲突无法被检测:打开两个标签页编辑同一条Department记录,先保存第一个标签页的修改,再在未刷新的第二个标签页保存修改,系统无任何并发冲突提示,直接覆盖数据库记录,所有并发检查代码被跳过。手动修改代码中的ConcurrencyToken也无法触发冲突检测。

核心原因

  1. 手动覆盖并发令牌:在OnPostAsync中手动设置departmentToUpdate.ConcurrencyToken = Guid.NewGuid().ToByteArray();,直接替换了从数据库加载的原始令牌,导致EF Core无法用客户端提交的旧令牌与数据库当前令牌做对比。
  2. 未关联客户端提交的令牌:加载数据库实体后,没有将表单提交的ConcurrencyToken赋值给要更新的实体,EF Core无法识别这是一个基于旧版本的更新操作。

修复步骤

1. 移除手动设置令牌的代码

删除OnPostAsync中这行代码:

departmentToUpdate.ConcurrencyToken = Guid.NewGuid().ToByteArray();

2. 关联客户端提交的并发令牌

在更新实体属性后,添加代码将表单提交的令牌赋值给加载的数据库实体:

// 手动更新属性
departmentToUpdate.Name = Department.Name;
departmentToUpdate.Budget = Department.Budget;
departmentToUpdate.StartDate = Department.StartDate;
departmentToUpdate.InstructorID = Department.InstructorID;

// 新增:将客户端提交的旧并发令牌赋值给要更新的实体
departmentToUpdate.ConcurrencyToken = Department.ConcurrencyToken;

3. (可选)显式配置并发令牌(增强稳定性)

在SchoolContext的OnModelCreating方法中,显式配置ConcurrencyToken为行版本:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Department>()
        .Property(d => d.ConcurrencyToken)
        .IsRowVersion(); // 标记为数据库自动维护的行版本
}

修改后的OnPostAsync关键代码片段

public async Task<IActionResult> OnPostAsync(int id)
{
    _logger.LogInformation("Starting to handle POST request for department with ID: {ID}", id);
    ModelState.Remove("Department.Administrator");

    var departmentToUpdate = await _context.Departments
        .Include(i => i.Administrator)
        .FirstOrDefaultAsync(m => m.DepartmentID == id);

    if (departmentToUpdate == null)
    {
        return HandleDeletedDepartment(id);
    }

    // 手动更新属性
    departmentToUpdate.Name = Department.Name;
    departmentToUpdate.Budget = Department.Budget;
    departmentToUpdate.StartDate = Department.StartDate;
    departmentToUpdate.InstructorID = Department.InstructorID;

    // 关联客户端提交的旧并发令牌
    departmentToUpdate.ConcurrencyToken = Department.ConcurrencyToken;

    // 处理Administrator关联逻辑...
    if (Department.InstructorID.HasValue)
    {
        departmentToUpdate.Administrator = await _context.Instructors
            .FindAsync(Department.InstructorID.Value);
    }
    else
    {
        departmentToUpdate.Administrator = null;
    }

    if (!ModelState.IsValid)
    {
        InstructorNameSL = new SelectList(_context.Instructors, "ID", "FullName", departmentToUpdate.InstructorID);
        return Page();
    }

    try
    {
        await _context.SaveChangesAsync();
        return RedirectToPage("./Index");
    }
    catch (DbUpdateConcurrencyException ex)
    {
        // 原有并发冲突处理逻辑...
        _logger.LogError(ex, "Concurrency conflict for department with ID: {ID}", departmentToUpdate.DepartmentID);
        var exceptionEntry = ex.Entries.Single();
        var databaseEntry = await exceptionEntry.GetDatabaseValuesAsync();
        
        if (databaseEntry == null)
        {
            ModelState.AddModelError(string.Empty, "Unable to save changes. The department was deleted by another user.");
        }
        else
        {
            var dbValues = (Department)databaseEntry.ToObject();
            ModelState.AddModelError(string.Empty, "The record you attempted to edit was modified by another user. If you still want to edit this record, click Save again. Otherwise, click Cancel.");
            Department.ConcurrencyToken = (byte[])dbValues.ConcurrencyToken;
        }

        InstructorNameSL = new SelectList(_context.Instructors, "ID", "FullName", departmentToUpdate.InstructorID);
        return Page();
    }

    InstructorNameSL = new SelectList(_context.Instructors, "ID", "FullName", departmentToUpdate.InstructorID);
    return Page();
}

验证方式

  1. 打开两个标签页进入同一条Department的编辑页面
  2. 在第一个标签页修改属性并保存
  3. 返回第二个未刷新的标签页,修改属性并保存
  4. 此时系统会触发DbUpdateConcurrencyException,进入异常处理分支,显示并发冲突提示信息

内容的提问来源于stack exchange,提问作者user24313025

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:54:57