Efcore: .NET 5.0 RC1 Table-per-type (TPT): InvalidOperationException when trying to add two different new entity instances to same DbContext

Created on 17 Sep 2020  路  1Comment  路  Source: dotnet/efcore

Trying out the new Table-per-type (TPT) mapping feature, I get the following InvalidOperationException "The instance of entity type 'Dog' cannot be tracked because another instance with the key value '{Id: 0}' is already being tracked. ..:" when trying to add two new different instances of the sub or parent class to the same DbContext.

The exception occurs in 5.0.0-rc.1.20451.13 and 6.0.0-alpha.1.20465.1.
It works fine with 5.0.0-preview.8.20407.4!

Exception:

System.InvalidOperationException: The instance of entity type 'Dog' cannot be tracked because another instance with the key value '{Id: 0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
   at EfcBug.Program.Main(String[] _) in C:\Users\paule\Downloads\EFC_Bug\EFC_Bug\Program.cs:line 68

Steps to reproduce:

``` C#
namespace EfcBug
{
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

[Table( "Animals" )]
public class Animal
{
    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.Identity )]
    public int Id { get; set; }
    public string Species { get; set; }
}

[Table( "Pets" )]
public class Pet : Animal
{
    public string Name { get; set; }
}

[Table( "Cats" )]
public class Cat : Pet
{
    public string EdcuationLevel { get; set; }
}

[Table( "Dogs" )]
public class Dog : Pet
{
    public string FavoriteToy { get; set; }
}

public sealed class EfBugDbContext : DbContext
{
    protected override void OnConfiguring( DbContextOptionsBuilder options )
    {
        options
            .UseSqlServer(
                "Data Source=localhost;Initial Catalog=TestDB_EfBug;Persist Security Info=True;User ID=User;Password=Pass",
                providerOptions => providerOptions.EnableRetryOnFailure() )
            .EnableDetailedErrors()
            .EnableSensitiveDataLogging();
    }

    protected override void OnModelCreating( ModelBuilder modelBuilder )
    {
        modelBuilder.Entity<Animal>().ToTable( "Animals" );
        modelBuilder.Entity<Pet>().ToTable( "Pets" );
        modelBuilder.Entity<Cat>().ToTable( "Cats" );
        modelBuilder.Entity<Dog>().ToTable( "Dogs" );
    }
}

public sealed class Program
{
    static void Main( string[] _ )
    {
        try
        {
            using( EfBugDbContext db = new EfBugDbContext() )
            {
                db.Database.EnsureCreated();
            }

            using( EfBugDbContext db = new EfBugDbContext() )
            {
                db.Add( new Dog() { Name = "Woof", FavoriteToy = "Bone" } );
                db.Add( new Dog() { Name = "Woof", FavoriteToy = "Bone" } );

                db.SaveChanges();
            }

            Console.WriteLine( "OK" );
        }
        catch( Exception ex )
        {
            Console.WriteLine( ex.ToString() );
        }

        Console.ReadLine();
    }
}

}


``` XML
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Configurations>Debug;Release;TestRelease;ReleaseKundeProd;ReleaseKundeTest</Configurations>
  </PropertyGroup>

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>EfcBug</RootNamespace>
    <AssemblyName>EfcBug</AssemblyName>
  </PropertyGroup>

  <PropertyGroup>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <LangVersion>latest</LangVersion>
    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
    <Prefer32Bit>false</Prefer32Bit>
    <StartupObject>EfcBug.Program</StartupObject>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0-alpha.1.20465.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0-alpha.1.20465.1">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="6.0.0-alpha.1.20465.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0-alpha.1.20465.1" />
  </ItemGroup>

  <!--<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0-rc.1.20451.13" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0-rc.1.20451.13">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="5.0.0-rc.1.20451.13" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-rc.1.20451.13" />
  </ItemGroup>-->

  <!--<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0-preview.8.20407.4" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0-preview.8.20407.4">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="5.0.0-preview.8.20407.4" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-preview.8.20407.4" />    
  </ItemGroup>-->

</Project>

Further technical details

EF Core version: 5.0.0-rc.1.20451.13 (doesn't work), 6.0.0-alpha.1.20465.1 (doesn't work), 5.0.0-preview.8.20407.4 (works fine!)
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.1.8
Operating system: Windows 10 2004
SQL Server 15.0.4063.15
IDE: Visual Studio 2019 16.7.3

Servicing-approved closed-fixed customer-reported type-bug

Most helpful comment

Note for triage: value generation is broken. The Added entity is marked as ValueGenerated.OnAdd, but remains zero.

Model:

Model: 
  EntityType: Animal
    Properties: 
      Id (int) Required PK FK AfterSave:Throw ValueGenerated.OnAdd
      Species (string)
    Keys: 
      Id PK
  EntityType: Cat Base: Pet
    Properties: 
      EdcuationLevel (string)
    Foreign keys: 
      Cat {'Id'} -> Pet {'Id'} Unique ClientCascade
  EntityType: Dog Base: Pet
    Properties: 
      FavoriteToy (string)
    Foreign keys: 
      Dog {'Id'} -> Pet {'Id'} Unique ClientCascade
  EntityType: Pet Base: Animal
    Properties: 
      Name (string)
    Foreign keys: 
      Pet {'Id'} -> Animal {'Id'} Unique ClientCascade

>All comments

Note for triage: value generation is broken. The Added entity is marked as ValueGenerated.OnAdd, but remains zero.

Model:

Model: 
  EntityType: Animal
    Properties: 
      Id (int) Required PK FK AfterSave:Throw ValueGenerated.OnAdd
      Species (string)
    Keys: 
      Id PK
  EntityType: Cat Base: Pet
    Properties: 
      EdcuationLevel (string)
    Foreign keys: 
      Cat {'Id'} -> Pet {'Id'} Unique ClientCascade
  EntityType: Dog Base: Pet
    Properties: 
      FavoriteToy (string)
    Foreign keys: 
      Dog {'Id'} -> Pet {'Id'} Unique ClientCascade
  EntityType: Pet Base: Animal
    Properties: 
      Name (string)
    Foreign keys: 
      Pet {'Id'} -> Animal {'Id'} Unique ClientCascade
Was this page helpful?
0 / 5 - 0 ratings