繁体   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