EF Core 重复键:无法跟踪实体类型 '' 的实例,因为已跟踪具有键值 '' 的另一个实例

时间:2021-06-11 19:56:27

标签: c# entity-framework-core blazor change-tracking

我正在 Blazor 服务器中使用 EF Core 处理表单。我在实体跟踪方面遇到了许多问题,因此我将所有查询设置为 AsNoTracking,并将我的服务设计为为每个查询创建一个新的 dbcontext 实例。我认为这是合适的,因为不会编辑任何返回值 - 只会存储用户输入的表单数据和对查询字段(例如员工编号)的 id 引用。对于插入数据,我使用 this:

using var context = Factory.CreateDbContext();
context.SetupForm.Attach(model);
context.Entry(model).State = EntityState.Added;
await context.SaveChangesAsync();

我是附加数据而不是添加数据,然后将表单对象状态设置为已添加。这可确保 EF Core 在插入表单数据时不会尝试插入现有员工对象。

问题始于表单的一部分,该部分可以包含用户想要的任意数量的项目。选择几个员工并输入相关数据。当他们提交表单时,他们可能在多个项目中选择了同一名员工。由于这些员工是从不同的上下文中选择的,因此它们是具有相同 ID 的两个独立实例。当然,EF Core 不喜欢这样,会抛出这样的错误:

The instance of entity type 'Principal' cannot be tracked because another instance with the key value '{EmployeeID: 1234}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

我理解为什么会发生此错误,但我需要能够以这种方式附加多个实体。我该如何解决这个问题?

我可以做的一件事是手动分配外键,但这会很严格,并且需要在模型更改时进行更新。

2 个答案:

答案 0 :(得分:0)

试试这个

using var context = Factory.CreateDbContext();

context.Set<Principal>().Add(model);
//or maybe context.Principals.Add(model);

await context.SaveChangesAsync();

答案 1 :(得分:-1)

这似乎奏效了!它的作用是将缺少密钥的任何实体标记为已添加。否则,该实体将被完全忽略。

using var context = Factory.CreateDbContext();
context.ChangeTracker.TrackGraph(model, node =>
{
     if (!node.Entry.IsKeySet)
     {
          node.Entry.State = EntityState.Added;
     }
});
await context.SaveChangesAsync();

不需要插入任何有键的项目。将它们视为未跟踪,然后解决任何重复的问题,并只插入需要它的行。

更多信息:https://docs.microsoft.com/en-us/ef/core/change-tracking/identity-resolution#resolve-duplicates