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

使用ASP.NET Web API 2+EF6结合LocalDB时触发DbUpdateConcurrencyException

解决EF6调用SaveChanges()时的DbUpdateConcurrencyException异常

我之前在做ASP.NET Web API 2 + EF6的项目时,也碰到过LocalDB环境下SaveChanges抛出这个并发异常的情况,给你整理几个最可能的原因和解决思路:

1. 检查实体的并发令牌配置

这个异常本质是EF检测到你要操作的记录,在读取到修改的间隙里状态发生了变化——但本地开发大概率不是真的多用户并发,而是实体的并发配置出了问题。

  • 如果你的实体类里不小心加了[Timestamp]或者[ConcurrencyCheck]特性,EF会默认把这些字段当成并发令牌,每次更新都会对比字段值,不匹配就会抛异常。如果不需要并发控制,可以直接去掉这些特性;
  • 如果确实需要并发控制,那要确保更新时拿到最新的令牌值,或者在捕获异常后重新读取实体再尝试更新。

举个错误配置的实体示例:

public class UserData
{
    public int Id { get; set; }
    public string Content { get; set; }
    // 误加的Timestamp特性,导致每次更新都要校验这个值
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

2. 确认实体状态是否正确

Web API接收前端数据后,很容易出现EF对实体状态识别错误的情况:

  • 新建实体:要确保数据库里主键是自增(Identity)配置,并且你没有手动给主键赋值——如果手动设置了主键,EF可能会把它当成已存在的实体去更新,结果数据库里找不到就触发异常;
  • 更新实体:不要直接把前端传来的实体Attach到DbContext,正确的做法是先从DbContext查询出数据库中已有的实体,再把前端的属性值赋值过去,最后调用SaveChanges。

正确的更新逻辑示例:

public IHttpActionResult UpdateData(int id, UserData model)
{
    var existingData = db.UserDatas.Find(id);
    if (existingData == null)
    {
        return NotFound();
    }
    // 手动赋值或者用AutoMapper做属性映射
    existingData.Content = model.Content;
    // 其他属性赋值...
    db.SaveChanges();
    return Ok(existingData);
}

3. 排查LocalDB的文件或连接问题

LocalDB的数据库文件如果被其他进程锁定(比如同时开着SSMS连接数据库),或者文件权限不足,也可能间接触发这个异常:

  • 先关闭所有可能连接LocalDB的工具(比如SSMS、Visual Studio的服务器资源管理器),再重新测试;
  • 检查LocalDB数据库文件所在文件夹的权限,确保当前用户有读写权限。

4. 异常捕获与重试逻辑(针对真实并发场景)

如果你的接口确实存在多用户并发操作的可能,可以在捕获异常后重新读取数据再尝试更新:

public bool SaveWithRetry()
{
    const int maxRetryTimes = 3;
    int retryCount = 0;

    while (retryCount < maxRetryTimes)
    {
        try
        {
            db.SaveChanges();
            return true;
        }
        catch (DbUpdateConcurrencyException ex)
        {
            retryCount++;
            var entry = ex.Entries.Single();
            // 从数据库加载当前最新的实体数据
            var dbValues = entry.GetDatabaseValues();
            
            if (dbValues == null)
            {
                // 实体已被其他操作删除
                throw new InvalidOperationException("目标数据已被删除");
            }
            // 将实体的原始值更新为数据库最新值,准备重试
            entry.OriginalValues.SetValues(dbValues);
        }
    }
    throw new InvalidOperationException("重试次数过多,保存失败");
}

建议你先从第2点开始排查,Web API里实体状态处理不当是触发这个异常最常见的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:39:11