【问题标题】:The instance of entity type 'Customer' cannot be tracked because another instance with the key value '{Id: ...}' is already being tracked无法跟踪实体类型“客户”的实例,因为已在跟踪另一个具有键值“{Id: ...}”的实例
【发布时间】:2019-12-29 03:59:59
【问题描述】:

我一直在寻找类似的问题,但它们对我帮助不大。在我看来,我的 DbContext 需要进行 Scoped 以防止这种情况发生。即使我之前实现了“AddScoped”,它仍然无法正常工作。

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
    {
        options.EnableSensitiveDataLogging();
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));

    }, ServiceLifetime.Scoped);

    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
         AddEntityFrameworkStores<ApplicationDbContext>();

    services.Configure<IdentityOptions>(options =>
    {
     ...
    });    
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddScoped<ISmartyService, SmartyService>();
}

数据库上下文:

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)
{
}

public DbSet<Brand> Brand { get; set; }
public DbSet<Car> Car { get; set; }
public DbSet<Customer> Customer { get; set; }
public DbSet<Expense> Expense { get; set; }
public DbSet<Expensetype> Expensetype { get; set; }

表格

汽车

public Guid Id { get; set; }

[ForeignKey("Customer")]
public Guid? Customer_Id { get; set; }

[ForeignKey("Brand")]
public Guid Brand_Id { get; set; }

public string Name { get; set; }

public int Purchase_Price { get; set; }

public int Selling_Price { get; set; }

public int Mileage { get; set; }        

public DateTime InCirculationSince { get; set; }

public DateTime Purchased_At { get; set; }

public DateTime Sold_At { get; set; }

public byte[] Picture { get; set; }

public Customer Customer { get; set; }

public Brand Brand { get; set; }

客户

public Guid Id { get; set; }

[Required]
public string Firstname { get; set; }

[Required]
public string Lastname { get; set; }

public string Address { get; set; }

[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }

[DataType(DataType.PhoneNumber)]
public string Telephone { get; set; }

品牌

public Guid Id { get; set; }

public string Brandname { get; set; }

其他表不需要atm。我没有机会为他们工作。我真的不能说我做错了什么。我相信我为上传实现的逻辑是正确的。这可能是我做错的部分。对于上传,我使用以下代码:

public void AddOrUpdateCar(Car car)
{
    if (car.Id == Guid.Empty)
    {
        dbContext.Car.Add(car);
    }
    else
    {
        //Where the error occurs
        dbContext.Car.Update(car);
    }

    dbContext.SaveChanges();
}

在控制器中:

        Car car = null;

        //Update Condition
        if (viewModel.Id != Guid.Empty)
        {
            car = service.GetCar(viewModel.Id);

            car.Name = service.GetBrandAsString(viewModel.Brand) + " " + viewModel.Name;
            car.Brand_Id = viewModel.Brand;
            car.Purchase_Price = viewModel.Purchase_Price;
            car.Mileage = viewModel.Mileage;
            car.InCirculationSince = viewModel.InCirculationSince;
            car.Purchased_At = viewModel.Purchased_At;

            if (viewModel.Customer != null)
            {
                car.Customer_Id = viewModel.Customer.Id;

                //Applying changes to customer
                car.Customer.Firstname = viewModel.Customer.Firstname;
                car.Customer.Lastname = viewModel.Customer.Lastname;
                car.Customer.Address = viewModel.Customer.Address;
                car.Customer.Email = viewModel.Customer.Email;
                car.Customer.Telephone = viewModel.Customer.Telephone;
            }
        }
        //Add condition
        else
        {
            car = new Car()
            {
                Name = service.GetBrandAsString(viewModel.Brand) + " " + viewModel.Name,
                Brand_Id = viewModel.Brand,
                Purchase_Price = viewModel.Purchase_Price,
                Mileage = viewModel.Mileage,
                InCirculationSince = viewModel.InCirculationSince,
                Purchased_At = viewModel.Purchased_At                  
            };
        }

        if (viewModel.Picture != null)
        {
            car.Picture = ResizeImage(viewModel.Picture, 285, 144);
        }

        service.AddOrUpdateCar(car);

完整的错误信息

System.InvalidOperationException: 'The instance of entity type 'Customer' cannot be tracked because another instance with the key value '{Id: 626c03d3-4d66-44db-acad-1342dd9bc4ae}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'

任何帮助将不胜感激!任何可以让这个问题变得不那么痛苦的帮助

【问题讨论】:

  • 我在尝试更新通过另一个 dbContext 获取的实体时看到了这个错误。在您的情况下,我怀疑“服务”是罪魁祸首。它作为范围服务添加到哪里?
  • 不清楚您提供的哪一行代码导致您的标题出现错误。另外,请提供完整的错误消息。

标签: c# asp.net-mvc entity-framework-core


【解决方案1】:

在您的控制器代码中,您正在创建 Car 实体的新实例以更新它(我假设...因为您使用 viewModel.Id 作为 ID)。

因为你正在创建这个实例,而不是从上下文中检索它,所以它没有被上下文跟踪,当你尝试更新时你会得到这个错误,因为你新创建的Id实例的Car匹配上下文已经在跟踪的那个。

为了更新现有实体,您需要先从上下文中检索它,然后根据需要更改它的属性,然后Update it...

var car = dbContext.Car.Single(x => x.Id == viewModel.Id);

car.Name = "New Name";

dbContext.Car.Update(car);

【讨论】:

    【解决方案2】:

    经过大量尝试,我终于能够解决问题。即使我以前这样更新客户:

    car.Customer = viewModel.Customer;
    

    它没有应用更改。我相信 EF Core 认为没有任何改变,我正在尝试添加一个具有相同 ID 的新项目。因此,在告诉 EF Core 客户已通过应用更改进行了更改后,它运行良好。

    为了解释我的答案,我更改了问题中的代码。我不得不更改控制器中的代码。

    【讨论】:

      猜你喜欢
      • 2023-01-03
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 2021-11-24
      • 2020-10-16
      相关资源
      最近更新 更多