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

使用await修饰_context.Entry(job)报错及乐观并发问题求助

问题解答

1. 关于_context.Entry(job)无法使用await的问题

DbContext.Entry()是同步方法,直接返回DbEntityEntry<Job>对象,并不返回Task类型,因此完全不需要(也不能)用await修饰。直接移除await即可解决错误:

var entry = _context.Entry(job); // 正确写法,无需await

2. 乐观并发错误的解决方案

你遇到的DbUpdateConcurrencyException和OnBeforeSave是否用await无关,本质是:从ViewModel映射得到的job对象中**并发令牌(TimeStamp)**与数据库当前存储的版本不一致。以下是具体修复步骤:

步骤1:确认并发令牌配置正确

确保Job实体的TimeStamp属性已配置为EF的并发令牌,比如用数据注解:

public class Job
{
    // 其他属性...
    [Timestamp]
    public byte[] TimeStamp { get; set; }
}

或Fluent API:

modelBuilder.Entity<Job>()
    .Property(j => j.TimeStamp)
    .IsRowVersion();

步骤2:更新前获取数据库最新的并发令牌

因为你直接从ViewModel映射job并Attach到上下文,这个job的TimeStamp是前端提交的旧值,和数据库最新版本不匹配,导致并发校验失败。可以通过两种方式解决:

方案A:仅获取最新TimeStamp

// 在Attach前,查询数据库获取当前job的TimeStamp
var currentJobTimeStamp = await _context.Jobs
    .Where(j => j.Id == command.Id)
    .Select(j => j.TimeStamp)
    .FirstOrDefaultAsync(cancellationToken);

// 将最新TimeStamp赋值给映射后的job
job.TimeStamp = currentJobTimeStamp;

// 执行后续逻辑
OnBeforeAttach(job);
_context.Set<DataAccess.Domain.Lab.Job>().Attach(job);
OnBeforeSave(job); // 此方法无异步操作,无需await
await _context.SaveChangesAsync(cancellationToken);

方案B:加载完整实体并更新(更稳妥)

这种方式由EF自动跟踪属性变化,无需手动标记修改:

// 从数据库加载最新的job实体
var existingJob = await _context.Jobs.FindAsync(new object[] { command.Id }, cancellationToken);
if (existingJob == null)
{
    throw new KeyNotFoundException($"Job with Id {command.Id} not found.");
}

// 将ViewModel属性映射到现有实体
_mapper.Map(jobViewModel, existingJob);

// 直接保存,EF自动处理并发校验
await _context.SaveChangesAsync(cancellationToken);
return jobViewModel;

步骤3:调整OnBeforeSave逻辑(若坚持用Attach方式)

该方法内无异步操作,无需定义为async Task,同时确保并发令牌的修改标记正确:

private void OnBeforeSave(Job job)
{
    var entry = _context.Entry(job);
  
    if (job.IsNew)
    {
        entry.State = EntityState.Added;
    }
    else
    {
        entry.State = EntityState.Unchanged;
        // 标记需要更新的属性
        entry.Property(j => j.Name).IsModified = true;
        entry.Property(j => j.Description).IsModified = true;
        entry.Property(j => j.SAPCode).IsModified = true;
        entry.Property(j => j.InitiatedOn).IsModified = true;
        entry.Property(j => j.EndDate).IsModified = true;
        entry.Property(j => j.ProjectId).IsModified = true;
        // 并发令牌必须保持修改标记,用于EF并发校验
        entry.Property(j => j.TimeStamp).IsModified = true;
        // 禁止修改创建信息
        entry.Property(e => e.CreatedBy).IsModified = false;
        entry.Property(e => e.CreatedOn).IsModified = false;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:54:25