如何从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
相关产品推荐
相关产品推荐

