繁体   English   中英

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

[英]The instance of entity type cannot be tracked even with AsNoTracking

我在测试环境中收到错误,但在 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

此错误意味着在DbContext (上下文)的生命周期 scope 内,该实体已经被加载并正在被跟踪。 这可以直接通过不同的方法调用,或者间接通过作为另一个实体加载的一部分被急切或延迟加载。 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类的东西并希望确保任何已跟踪的实体可用并刷新它的任何其他情况。

只需检查以下内容。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM