在 EntityFramworkCore.InMemory 提供商中添加 ID = 0 的实体时出现问题

Problem adding entity with Id = 0 in EntityFramworkCore.InMemory provider

以下代码抛出异常:

System.InvalidOperationException: The instance of entity type 'DimEntity' cannot be tracked because another instance with the same key value for {'EntityEntityId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached

var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseInMemoryDatabase("Test");
using (var dbContext = new MyDbContext(optionsBuilder.Options))
{
    //when I comment this line, the rest works file
    dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 0, EntityKey = "Uknown" });


    //otherwise this line throws the exception
    dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 1, EntityKey = "DFS Region" });
    = "Europe Region" }); 
   dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 2, EntityKey = "Europe Region" });
}

为什么?

其他详细信息:

public partial class MyDbContext : DbContext
{
    public MyDbContext (DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }

    public virtual DbSet<DimEntity> DimEntity { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<DimEntity>(entity =>
        {
            entity.HasKey(e => e.EntityEntityId);
            entity.ToTable("DimEntity", "mm");
            entity.Property(e => e.EntityEntityId).HasColumnName("Entity_EntityID");
        });
    }
}

public partial class DimEntity
{
    public int EntityEntityId { get; set; }
    public string EntityKey { get; set; }
}

它不是特定于内存提供程序的。按照约定 int PK 被视为自动递增 (SqlServer identity),因此问题类似于向自动递增列添加显式值时的问题。

如果将 new DimEntity { EntityEntityId = 0, ... } 保存在变量中,您会看到 Add 之后 EntityEntityId 的值将为 1(因为当 PK 值为默认值时( 0 表示 int),执行 value generation on add)。

但是当您添加具有非默认 int PK 的实体时,不会生成任何值并且会为 EntityEntityId = 1 抛出异常,因为它已经存在 - 为您创建的第一个实体生成的值先添加。

一般来说,如果您不想生成 PK 值,您应该在 OnModelCreating:

中选择加入
entity.Property(e => e.EntityEntityId)
    .HasColumnName("Entity_EntityID")
    .ValueGeneratedNever(); // <--

如果您确定在创建实体时(即在您的业务逻辑和测试代码中)总是明确地为实体的 ID 字段赋值,只需用 属性 注释=21=] 设置为 DatabaseGeneratedOption.None:

public partial class DimEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int EntityEntityId { get; set; }
    public string EntityKey { get; set; }
}

三种可能DatabaseGeneratedOption values None, Identity, Computed correspond to the fluent methods ValueGeneratedNever, ValueGeneratedOnAdd, ValueGeneratedOnAddOrUpdate. The fluent syntax also offers ValueGeneratedOnUpdate看似多余,但如果你需要它就在那里。