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

I have this bookmark that has a relation with a category, so every time I update an existing bookmark, a new category should be created or updated if it already exists.我有这个与类别有关系的书签,所以每次我更新现有书签时,如果它已经存在,则应该创建或更新一个新类别。 When I update an existing bookmark I get this error:当我更新现有书签时,我收到此错误:

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'} 的实例。 When attaching existing entities, ensure that only one entity instance with a given key value is attached.附加现有实体时,请确保仅附加一个具有给定键值的实体实例。 Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。

My Entity looks like this:我的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; }
}

My Update Controller looks like this:我的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);
    }

My CreateCategory service looks like this:我的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;
    }

And my UpdateBookmark service looks like this:我的UpdateBookmark服务如下所示:

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

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

My GetBookmark() method我的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();
    }

The problem is here:问题在这里:

await _bookmarkService.UpdateBookmark(bookmark);

This is causing an Identity Resolution violation.这会导致身份解析违规。 Here's an excerpt from the link(with added emphasis):这是链接的摘录(特别强调):

A DbContext can only track one entity instance with any given primary key value. DbContext 只能跟踪一个具有任何给定主键值的实体实例 This means multiple instances of an entity with the same key value must be resolved to a single instance.这意味着必须将具有相同键值的实体的多个实例解析为单个实例。

The change tracker begins to track the Bookmark soon after the execution of this statement:更改跟踪器在执行此语句后不久就开始跟踪Bookmark

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

Change tracking is a feature of EF Core wherein any changes made to an entity is tracked after it is fetched from the database.更改跟踪是 EF Core 的一项功能,其中对实体所做的任何更改都会在从数据库中获取后进行跟踪。 All these changes will be applied as soon as you call context.SaveChanges() .所有这些更改将在您调用context.SaveChanges()后立即应用。

Now, if EF Core sees any other Bookmark instance other than the instance in exists with the same primary key, it throws an error.现在,如果 EF Core 发现除 in 中的实例之外的任何其他Bookmark实例exists相同的主键,则会引发错误。 In your case:在你的情况下:

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

In the above statement, bookmark is another instance of Bookmark with the same primary key( Bookmark.ID ).在上面的语句中, bookmark是具有相同主键( Bookmark.ID )的Bookmark的另一个实例。 This ID is being set from the post request during model binding.此 ID 是在 model 绑定期间从发布请求设置的。 So, in order to get around this, you have to either disable change tracking using AsNoTracking() :因此,为了解决这个问题,您必须使用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();
    

Or, the better option would be to make changes in the same instance that was fetched from the database(in your case, exists ).或者,更好的选择是在从数据库中获取的同一个实例中进行更改(在您的情况下, exists )。 You are also assigning the newly created category to bookmark.Category without checking if the Bookmark already contains another category.您还将新创建的category分配给bookmark.Category ,而不检查Bookmark是否已经包含另一个类别。 Check if the bookmark already contains a category, then change the name of this category if it exists and create a new one only if there is no existing category.检查书签是否已经包含一个类别,如果存在则更改此类别的名称,并仅在不存在现有类别时创建一个新类别。

It also appears that you do not need the mapped bookmark, so I've completely gotten rid of it and renamed exists to bookmark .您似乎也不需要映射的书签,所以我完全摆脱了它并将exists重命名为bookmark I've assumed that the request contains a property ID .我假设request包含一个属性ID Use the property that contains the bookmark 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.

相关问题 无法跟踪实体类型“Entity”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'Entity' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 实体类型的实例 <T> 无法跟踪,因为已经跟踪了另一个具有相同的{&#39;Id&#39;}键值的实例 - The instance of entity type <T> cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型 Model 的实例,因为已跟踪另一个具有相同 {&#39;Id&#39;} 键值的实例 - The instance of entity type Model cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“Bus”的实例,因为已经在跟踪具有相同键值 {'Id'} 的另一个实例 - The instance of entity type ‘Bus’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked 无法跟踪实体类型“AppUser”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'AppUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“IdentityUser”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'IdentityUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“Item”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'Item' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型的实例,因为已跟踪另一个具有与 {'Id'} 相同键值对的实例 - The instance of the entity type cannot be tracked because another instance with the same key value pair for{'Id'} is already being tracked 无法跟踪实体类型“ Article”的实例,因为已经跟踪了另一个具有相同键值的{&#39;Id&#39;}实例 - The instance of entity type 'Article' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“用户”的实例,因为已经在跟踪另一个具有相同键值的“Id”实例 - The instance of entity type 'User' cannot be tracked because another instance with the same key value for 'Id' is already being tracked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM