【问题标题】:The instance of entity type cannot be tracked even with AsNoTracking即使使用 AsNoTracking 也无法跟踪实体类型的实例
【发布时间】:2022-01-04 05:59:57
【问题描述】:

我在测试环境中收到错误,但在 prod 环境中没有收到错误,即使尚未放置跟踪。

错误“GetUserAsync:System.InvalidOperationException:无法跟踪实体类型“UserEntity”的实例,因为已在跟踪另一个具有键值“{Id:1}”的实例。附加现有实体时,请确保只有一个附加了具有给定键值的实体实例。

代码:

internal async Task<UserEntity> GetUserAsync(CancellationToken cancellationToken)
{
    var result = await _userDataQuery.GetLatestUser(cancellationToken);
}

我已经加了AsNoTracking

public async Task<UserEntity> GetLatestUser(CancellationToken cancellationToken)
{
    var result = await this.Entities
                           .OrderByDescending(m => m.Id)
                           .AsNoTracking().FirstOrDefaultAsync();
    await Context.Entry(result).ReloadAsync();

    return result;
}

不确定这是否有帮助,但我也注意到两个环境之间的 postgreSQL 上的 pg_sequences 对于用户表是不同的,并且它们在表中都只有 1 条记录

测试环境:

last_value = 2

产品环境:

last_value = 1

【问题讨论】:

    标签: c# postgresql entity-framework linq


    【解决方案1】:

    此错误意味着在DbContext(上下文)的生命周期范围内,该实体已被加载并正在被跟踪。这可以直接通过不同的方法调用,或者间接通过作为另一个实体加载的一部分被急切或延迟加载。 Reload 将尝试跟踪实体,这将导致另一个匹配实例已被跟踪的错误。

    据我所知,您可能不想使用AsNoTracking(),因为您不能保证该实体尚未被跟踪。照常加载。

    var result = await this.Entities
                           .OrderByDescending(m => m.Id)
                           .FirstAsync();
    await Context.Entry(result).ReloadAsync();
    

    每当您使用*OrDefault() 风格时,您必须处理集合中可能没有项目的事实。如果您希望至少有一个,请使用First

    这里的缺点是即使已经从数据库中新加载了所需的项目,也会调用 Reload。由于我们无法假设所需的项目已被跟踪或尚未被跟踪,因此最佳选择可能是:

    var id = this.Entities
                 .OrderByDescending(m => m.Id)
                 .Select(x => x.Id)
                 .FirstAsync();
    
    var result = this.Entities.Local
                           .Where(m => m.Id == id)
                           .SingleOrDefault();
    if (result != null)
        await Context.Entry(result).ReloadAsync();
    else
        result = this.Entities
            .Where(m => m.Id == id)
            .Single();
    

    此代码在本地跟踪缓存中查找特定项目,如果找到它将重新加载它,否则它将从数据库中加载当前项目。

    这种方法(减去从数据库中选择 ID)将适用于您提前知道您想要什么特定实体而不是依赖于 FirstOrDefault 之类的任何其他情况,并希望确保任何已跟踪的实体都可用并刷新它。

    【讨论】:

    • 删除 AsNoTracking 有效,这是有道理的,谢谢。!
    【解决方案2】:

    只需检查以下内容。

    1. 无论您是在代码中的任何位置使用context.Update( 还是context.Entity.Update(。 (这可能会导致此类问题)
    2. 确保不要持有 DbContext 实例的时间过长。根据 MS 的建议,它们应该是 Transient 或 Scoped(而不是单例)。

    如果您在代码中的任何位置执行 context.Update( 并持有 DbContext 实例相当长的时间,那么您很有可能在 DbContext 生命周期内多次尝试更新同一个跟踪实体。

    【讨论】:

      猜你喜欢
      • 2019-10-28
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      • 2021-05-04
      • 2022-01-26
      • 2023-01-03
      • 1970-01-01
      • 2020-01-17
      相关资源
      最近更新 更多