Search code examples
c#entity-framework-corein-memory-database

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


Following code throws exception:

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" });
}

Why?

Additional Details:

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

Solution

  • It's not in memory provider specific. By convention int PKs are considered auto increment (SqlServer identity), so the problem is similar to when adding explicit values to auto increment column.

    If you keep your new DimEntity { EntityEntityId = 0, ... } in a variable, you'll see that after Add the value of the EntityEntityId will be 1 (because when the PK value is default (0 for int), the value generation on add is performed).

    But when you add entity with non default int PK, no value generation occurs and the exception is thrown for EntityEntityId = 1 because it already exist - the generated value for the first entity you've added first.

    In general, if you don't want PK value generation, you should opt-in for that inside OnModelCreating:

    entity.Property(e => e.EntityEntityId)
        .HasColumnName("Entity_EntityID")
        .ValueGeneratedNever(); // <--