即使使用 AsNoTracking 也无法跟踪实体类型的实例

The instance of entity type cannot be tracked even with AsNoTracking

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

Error "GetUserAsync: System.InvalidOperationException: The instance of entity type 'UserEntity' cannot be tracked because another instance with the key value '{Id: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

代码:

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 对于用户 Table 是不同的,并且它们在 [=30= 中只有 1 条记录]

测试环境:

last_value = 2

产品环境:

last_value = 1

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

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

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

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

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

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 之类的东西并希望确保任何已经跟踪的实体可用并刷新它。

只需检查以下内容。

  1. 无论您是在代码中的任何地方执行 context.Update( 还是 context.Entity.Update(。 (这可能会导致此类问题)
  2. 确保不要将 DbContext 实例保留太久。根据 MS 的建议,它们应该是 Transient 或 Scoped(而不是单例)。

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