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

如何在Entity Framework中触发DbUpdateConcurrencyException?Web农场适配测试

解决EF 6中DbUpdateConcurrencyException触发失败的问题

为什么嵌套Parallel循环无法触发异常

EF的DbContext不是线程安全的,在并行循环中共享同一个上下文实例会导致状态跟踪混乱,无法正确模拟真实的并发场景。这种情况下的错误通常是线程安全问题而非预期的并发冲突异常。

正确触发DbUpdateConcurrencyException的步骤

1. 配置实体的并发令牌

首先确保你的实体已配置并发令牌(对应SQL Server的ROWVERSION类型):

public class YourEntity
{
    public int Id { get; set; }
    public string Data { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; } // 并发令牌字段
}

通过[Timestamp]特性标记该字段后,EF会在更新时自动对比数据库中的RowVersion值,不一致则抛出DbUpdateConcurrencyException。

2. 使用独立DbContext实例模拟并发

每个并发操作必须使用独立的DbContext,模拟Web农场中不同请求的独立上下文:

var targetEntityId = 1; // 待更新的实体ID

// 启动两个并行任务,每个任务持有独立上下文
var task1 = Task.Run(async () =>
{
    using (var context = new YourDbContext())
    {
        var entity = await context.YourEntities.FindAsync(targetEntityId);
        entity.Data = "更新自任务1";
        await Task.Delay(1000); // 延迟确保另一个任务已获取初始实体
        await context.SaveChangesAsync();
    }
});

var task2 = Task.Run(async () =>
{
    using (var context = new YourDbContext())
    {
        var entity = await context.YourEntities.FindAsync(targetEntityId);
        entity.Data = "更新自任务2";
        await Task.Delay(1000);
        try
        {
            await context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            Console.WriteLine("并发冲突触发成功:" + ex.Message);
            // 处理逻辑示例:获取数据库最新值并决定后续操作
            var entry = ex.Entries.Single();
            var dbValues = await entry.GetDatabaseValuesAsync();
            if (dbValues != null)
            {
                entry.OriginalValues.SetValues(dbValues);
                // 可选:重试保存或合并更改
                // await context.SaveChangesAsync();
            }
        }
    }
});

await Task.WhenAll(task1, task2);

3. 关键注意事项

  • 每个线程/任务用独立DbContext:这是模拟Web农场多节点并发的核心,每个请求都有独立的上下文实例。
  • 延迟操作确保并发条件:通过Task.Delay让两个任务都先获取到实体的初始版本,再执行更新,保证第二个任务保存时数据库中的RowVersion已被第一个任务修改。
  • 正确处理异常:捕获DbUpdateConcurrencyException后,可通过entry.GetDatabaseValues()获取最新数据,再选择覆盖、合并或终止操作。

替代测试方案:多进程模拟

如果单进程并行任务仍无法触发异常,可以启动多个独立的控制台应用实例,同时对同一实体执行更新操作,更贴近Web农场的真实分布式场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:32:36