无法跟踪实体类型的实例,因为跟踪了具有相同键值的另一个实例

时间:2018-01-11 08:10:27

标签: .net entity-framework .net-core asp.net-core-2.0

我在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;
    }
}

6 个答案:

答案 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()