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

如何从DbContext获取已读取对象的IUpdateEntry并构造DbUpdateConcurrencyException

从DbContext获取已读取对象的IUpdateEntry并创建DbUpdateConcurrencyException

要实现你的需求,核心是利用EF Core的ChangeTracker获取已跟踪实体的条目,再将其转换为IUpdateEntry(EntityEntry本身实现了该接口),最后构造并发异常。以下是具体步骤:

1. 获取并确保实体被上下文跟踪

通过FirstOrDefaultAsync查询到的实体默认会被DbContext跟踪(除非使用AsNoTracking),先获取目标实体:

var existingEvent = await dbContext.Events.FirstOrDefaultAsync(e => e.Id == entity.Id);
if (existingEvent == null)
{
    throw new KeyNotFoundException("指定的事件不存在");
}

2. 从ChangeTracker获取对应的EntityEntry(即IUpdateEntry)

直接通过ChangeTracker.Entries查找实体对应的条目:

var entityEntry = dbContext.ChangeTracker.Entries<Event>()
    .FirstOrDefault(entry => entry.Entity == existingEvent);

// 如果实体未被跟踪(比如之前用了AsNoTracking),先附加到上下文再获取条目
if (entityEntry == null)
{
    dbContext.Events.Attach(existingEvent);
    entityEntry = dbContext.ChangeTracker.Entries<Event>()
        .First(entry => entry.Entity == existingEvent);
}

3. 构造DbUpdateConcurrencyException

由于你的场景是网页初始化时读取的实体RowVersion已过期,需要确保当前实体的RowVersion与数据库最新值不一致,再传入条目构造异常:

// 获取数据库中该实体的最新RowVersion
var dbLatestRowVersion = await dbContext.Events
    .Where(e => e.Id == entity.Id)
    .Select(e => e.RowVersion)
    .FirstOrDefaultAsync();

// 对比当前读取的RowVersion与数据库最新值,不一致则抛出异常
if (!existingEvent.RowVersion.SequenceEqual(dbLatestRowVersion))
{
    var concurrencyException = new DbUpdateConcurrencyException(
        "该数据已被其他用户修改,请刷新页面后重试。",
        new List<IUpdateEntry> { entityEntry });
    throw concurrencyException;
}

关键说明

  • IUpdateEntry是EntityEntry实现的接口,因此直接将EntityEntry实例传入异常即可
  • 若实体未被上下文跟踪,必须先调用Attach方法,让ChangeTracker生成对应的条目
  • 手动构造并发异常时,需确保实体的并发标记(如RowVersion)与数据库最新值不匹配,这样异常场景才符合业务逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:10:05