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

c# entity-framework-core in-memory-database

Question

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; }
}
1
2
11/21/2018 4:21:37 PM

Accepted Answer

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(); // <--
2
11/21/2018 4:35:19 PM

Popular Answer

If you are certain that you will always be explicitly assigning a value to the entity's ID field when creating it (i.e. in both your business logic and your test code), simply annotate your property with the DatabaseGeneratedAttribute set to DatabaseGeneratedOption.None:

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

The three possible DatabaseGeneratedOption values None, Identity, Computed correspond to the fluent methods ValueGeneratedNever, ValueGeneratedOnAdd, ValueGeneratedOnAddOrUpdate. The fluent syntax also offers ValueGeneratedOnUpdate which seems superfluous, but it's there if you need it.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow