簡體   English   中英

無法跟蹤實體類型“書簽”的實例,因為已經在跟蹤具有相同鍵值 {'ID'} 的另一個實例

[英]The instance of entity type 'Bookmark' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked

我有這個與類別有關系的書簽,所以每次我更新現有書簽時,如果它已經存在,則應該創建或更新一個新類別。 當我更新現有書簽時,我收到此錯誤:

無法跟蹤實體類型“Bookmark”的實例,因為已經在跟蹤另一個具有相同鍵值 {'ID'} 的實例。 附加現有實體時,請確保僅附加一個具有給定鍵值的實體實例。 考慮使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”來查看沖突的鍵值。

我的Entity看起來像這樣:

public class Bookmark
{
    [Key]
    public int ID { get; set; }

    [StringLength(maximumLength: 500)]
    public string URL { get; set; }

    public string ShortDescription { get; set; }

    public int? CategoryId { get; set; }

    public virtual Category Category { get; set; }

    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    public DateTime CreateDate { get; set; }
}

我的Update Controller 看起來像這樣:

public async Task<IActionResult> Edit(BookmarkViewModel request)
    {
        var bookmark = _mapper.Map<Bookmark>(request);

        var exists = await _bookmarkService.GetBookmark(bookmark.ID);
        if(exists == null)
            return new StatusCodeResult(Microsoft.AspNetCore.Http.StatusCodes.Status404NotFound);

        if (ModelState.IsValid)
        {
            if (request.CategoryName != null)
            {
                 var category = _categoryService.CreateCategory(new Category
                {
                    Name = request.CategoryName
                });

                bookmark.Category = category;
                bookmark.CategoryId = category.ID;
            }
            await _bookmarkService.UpdateBookmark(bookmark);

            return RedirectToAction("Index");
        }

        return View(bookmark);
    }

我的CreateCategory服務如下所示:

    public Category CreateCategory(Category category)
    {
        category.UserId = _identityService.GetUserId();

        var existing = _ReadLaterDataContext.Categories
            .FirstOrDefault(x => x.Name.Equals(category.Name) && x.UserId.Equals(category.UserId));
        if (existing != null)
            return existing;

        _ReadLaterDataContext.Add(category);
        _ReadLaterDataContext.SaveChanges();
        return category;
    }

我的UpdateBookmark服務如下所示:

public async Task UpdateBookmark(Bookmark bookmark)
    {
        bookmark.CreateDate = DateTime.Now;

        UpdateExistingCategory(bookmark);
        _ReadLaterDataContext.Update(bookmark);
        await _ReadLaterDataContext.SaveChangesAsync();
    }

我的GetBookmark()方法

public async Task<Bookmark> GetBookmark(int Id)
    {
        return await _ReadLaterDataContext.Bookmark.Where(x => x.ID == Id && x.UserId.Equals(_identityService.GetUserId())).Include(x => x.Category).FirstOrDefaultAsync();
    }

問題在這里:

await _bookmarkService.UpdateBookmark(bookmark);

這會導致身份解析違規。 這是鏈接的摘錄(特別強調):

DbContext 只能跟蹤一個具有任何給定主鍵值的實體實例 這意味着必須將具有相同鍵值的實體的多個實例解析為單個實例。

更改跟蹤器在執行此語句后不久就開始跟蹤Bookmark

var exists = await _bookmarkService.GetBookmark(bookmark.ID);

更改跟蹤是 EF Core 的一項功能,其中對實體所做的任何更改都會在從數據庫中獲取后進行跟蹤。 所有這些更改將在您調用context.SaveChanges()后立即應用。

現在,如果 EF Core 發現除 in 中的實例之外的任何其他Bookmark實例exists相同的主鍵,則會引發錯誤。 在你的情況下:

var bookmark = _mapper.Map<Bookmark>(request);

在上面的語句中, bookmark是具有相同主鍵( Bookmark.ID )的Bookmark的另一個實例。 此 ID 是在 model 綁定期間從發布請求設置的。 因此,為了解決這個問題,您必須使用AsNoTracking()禁用更改跟蹤:

public async Task<Bookmark> GetBookmark(int Id) 
    => await _ReadLaterDataContext.Bookmark
        .AsNoTracking()
        .Where(x => x.ID == Id 
             && x.UserId.Equals(_identityService.GetUserId()))
        .Include(x => x.Category)
        .FirstOrDefaultAsync();
    

或者,更好的選擇是在從數據庫中獲取的同一個實例中進行更改(在您的情況下, exists )。 您還將新創建的category分配給bookmark.Category ,而不檢查Bookmark是否已經包含另一個類別。 檢查書簽是否已經包含一個類別,如果存在則更改此類別的名稱,並僅在不存在現有類別時創建一個新類別。

您似乎也不需要映射的書簽,所以我完全擺脫了它並將exists重命名為bookmark 我假設request包含一個屬性ID 使用包含書簽 ID 的屬性:

public async Task<IActionResult> Edit(BookmarkViewModel request)
{
    var bookmark = await _bookmarkService.GetBookmark(request.ID);
    if (bookmark == null)
        return new StatusCodeResult(Microsoft.AspNetCore.Http.StatusCodes.Status404NotFound);

    if (ModelState.IsValid)
    {
        if (request.CategoryName is not null)
        {
            if (bookmark.Category is not null)
            {
                bookmark.Category.Name = request.CategoryName;
            }

            else
            {
                var category = _categoryService.CreateCategory(new Category
                {
                    Name = request.CategoryName
                });

                bookmark.Category = category;
                bookmark.CategoryId = category.ID;
            }
        }
        await _bookmarkService.UpdateBookmark(bookmark);

        return RedirectToAction("Index");
    }

    return View(request);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM