![](/img/trans.png)
[英]The instance of entity type 'Entity' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked
[英]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.