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

EF Core使用AsNoTracking查询后OriginalValues返回当前值问题

问题根源

你的问题核心是AsNoTracking()查询的特性和EF Core变更跟踪的原始值填充逻辑冲突导致的。

原理说明

  1. 当你使用AsNoTracking()执行查询时,EF Core为了优化性能,不会对返回的实体做属性快照,也不会将实体纳入上下文的跟踪列表,实体和上下文完全独立。
  2. 你后续调用DataContext.Entry(projeFound)将实体附加到上下文时,EF 没有该实体的历史快照数据,会用实体当前的属性值(也就是数据库查询出来的旧值)同时初始化OriginalValues和CurrentValues两个集合。
  3. 你的代码先调用entry.CurrentValues.SetValues(proje)将CurrentValues更新为传入的新值,再手动设置entry.State = EntityState.Modified。这时EF 检测到这是一个刚附加的、没有历史快照的实体,为了生成全字段更新的SQL语句,会将OriginalValues覆盖为当前CurrentValues的最新值,这就是你拿到的OriginalValues是当前值的原因。
  4. 去掉AsNoTracking()后,EF 在查询阶段就会为实体生成原始属性快照,后续不管你怎么修改CurrentValues、怎么修改实体状态,OriginalValues都会保留查询时的初始值,因此可以正常拿到旧值。

解决方案

方案1(推荐)

直接移除查询语句中的AsNoTracking(),使用默认的跟踪查询,不需要调整其他逻辑,EF 会自动维护原始值快照,是最稳妥的方案。

方案2(保留AsNoTracking)

如果你出于性能考量一定要用AsNoTracking(),调整代码执行顺序即可:先设置实体状态为Modified,再更新CurrentValues,避免OriginalValues被覆盖:

public async Task<ActionResult<int>> ProjeleriGuncelle(Proje proje)
{
    var projeFound = DataContext.Projeler.AsNoTracking().FirstOrDefault(p => p.EntegrasyonId == proje.EntegrasyonId);
    var entry = DataContext.Entry<Proje>(projeFound);

    // 先设置状态,此时OriginalValues和CurrentValues都是查询得到的旧值
    entry.State = EntityState.Modified;
    // 再更新CurrentValues为新值,OriginalValues不会被修改
    entry.CurrentValues.SetValues(proje);

    await DataContext.SaveChangesAsync();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 02:15:00