簡體   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