[英]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.