我在asp.net core 2.0中使用通用存储库模式,它无法处理存储库对象,当我要更新条目时,它已成功更新一次,但是当我尝试更新更新时,一旦它抛出以下例外:
无法跟踪实体类型“公司”的实例,因为已经跟踪了另一个具有{'ID'}相同键值的实例。附加现有实体时,请确保仅附加具有给定键值的一个实体实例。考虑使用'DbContextOptionsBuilder.EnableSensitiveDataLogging'来查看冲突的键值。
public ActionResult Edit(Int64 id, Company collection)
{
try
{
// TODO: Add update logic here
interfaceobj.updateModel(collection);
interfaceobj.Save();
return RedirectToAction(nameof(Index));
}
catch(Exception ex)
{
throw ex;
}
}
答案 0 :(得分:8)
您的数据库上下文被多个请求共享,这意味着您已经跟踪了您正在编辑的实体。
这很可能是因为您的存储库服务是Singleton而不是Scoped,因此您的数据库上下文在被拔出时被跟踪的实体重用,然后重新放入到同一个实例中。数据库上下文。
您应该做的是拥有 Scoped Repository ,这意味着将为每个请求创建一个新实例。同样,您还将拥有每请求数据库上下文。
当您注册服务时,它将使用services.AddSingleton<..>
将此更改为services.AddScoped<..>
,当您将其注入控制器时,您将获得每个请求的新实例,并且您的更新应该可以正常工作。
答案 1 :(得分:1)
就像Rudi Visser suggested一样,在多个数据上下文中使用一个实体时,您可能会遇到此问题。就我而言,这类似于以下内容:
User user = await DataContext.Users.SingleOrDefaultAsync(u => u.Id == "SomeId");
// Switch to UserManager *_*
var res = await UserManager.ResetPasswordAsync(user, token, password); // Exception thrown
一种简单的解决方案是尝试坚持使用DataContext
,因为UserManager
似乎在后台进行了一些附加和分离(也许)。例如:
User user = await UserManager.FindByIdAsync("SomeId");
var res = await UserManager.ResetPasswordAsync(user, token, password);
答案 2 :(得分:0)
也许可以帮助您:
services.AddDbContext<...>(ServiceLifetime.Singleton);
答案 3 :(得分:0)
您需要分离的条目。
Entry<CustomerBaseInfo>(data).State = EntityState.Detached;
答案 4 :(得分:0)
我遇到了同样的问题并用谷歌搜索,这是我的想法
实体框架具有更改跟踪器,实体使用其主键在更改跟踪器中存储和引用。更准确地说,dbcontext 有一个秘密字典,它只允许存储一个相同类型和相同主键的对象。它无法跟踪相同类型和相同主键的两个对象。这是我的示例代码。
var model = new EaEnrollment()
{
Id = 1,
UserId = 2,
AllocationType = "Individual",
Status = "In Progress"
};
_repoEaEnrollment.Update(model);
//here is the some other code that meets my businees requirement
//and changes the status to Completed and trying to update type a
model.Status = "Completed";
_repoEaEnrollment.Update(model); // exception .ie. it can not track
// two distinct instance. They are distinct becuase
//they have same typeand same primary key
我通过从变更跟踪器中分离第一个实例来解决。这是解决方案代码..
var model = new EaEnrollment()
{
Id = 1,
UserId = 2,
AllocationType = "Individual",
Status = "In Progress"
};
_repoEaEnrollment.Update(model);
_repoEaEnrollment.SaveChanges();
//here is the some other code that meets my businees requirement
//and changes the status to Completed and trying to update type a
//detach first instance from change tracker
_repoEaEnrollment.Detach(model);
//Update again
model.Status = "Completed";
_repoEaEnrollment.Update(model); // no exception
答案 5 :(得分:-1)
这将为您提供帮助!
AsNoTracking()