Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model configuration: Incorrect key discovery can result in exception saying another instance has same key, but it doesn't #7049

Closed
HappyNomad opened this issue Nov 18, 2016 · 3 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@HappyNomad
Copy link

HappyNomad commented Nov 18, 2016

The issue can be reproduced with this version:

"Microsoft.EntityFrameworkCore.SqlServer": "1.2.0-preview*",

and this context:

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

	public DbSet<L> Ls { get; set; }
	public DbSet<AL> ALs { get; set; }
}

and this model:

public class L
{
	public int ID { get; set; }
	public IList<T> Ts { get; set; }
}

public class T : P
{
	public Q D { get; set; }
	public P P { get; set; }
	public Q F { get; set; }
}

public class P : PBase { }

public class Q : PBase { }

public abstract class PBase
{
	public int ID { get; set; }
	public string Stuff { get; set; }
}

public class AL
{
	public int ID { get; set; }
	public PBase L { get; set; }
}

The "seeding" code is:

dataContext.Ls.Add(
	new L {
		Ts = new[] { new T { D = new Q(), F = new Q() } }
	}
);

The exception is:

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=The instance of entity type 'Q' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
       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)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode node)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph(EntityEntryGraphNode node, Func`2 handleNode)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph(EntityEntryGraphNode node, Func`2 handleNode)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph(EntityEntryGraphNode node, Func`2 handleNode)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState entityState)
       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 Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Add(TEntity entity)
       at EFGetStarted.AspNetCore.NewDb.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, BloggingContext dataContext) in C:\Users\Adrian\Development\Examples\ASP.NET Core\EFGetStarted.AspNetCore.NewDb\src\EFGetStarted.AspNetCore.NewDb\Startup.cs:line 61
  InnerException: 
@ajcvickers
Copy link
Member

Note for triage: Looks like ID in PBase, inherited by Q, is not getting ValueGenerated.OnAdd.

Here is the model:

Model: 
  EntityType: AL
    Properties: 
      ID (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
      LID (no field, Nullable<int>) Shadow FK Index 1 1 1 0 -1
    Navigations: 
      L (<L>k__BackingField, PBase) ToPrincipal PBase 0 -1 2 -1 -1
    Keys: 
      ID PK
    Foreign keys: 
      LID -> PBase.ID ToPrincipal: L
    Annotations: 
      Relational:TableName: ALs
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: L
    Properties: 
      ID (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
    Navigations: 
      Ts (<Ts>k__BackingField, IList<T>) Collection ToDependent T 0 -1 1 -1 -1
    Keys: 
      ID PK
    Annotations: 
      Relational:TableName: Ls
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: P Base: PBase
    Annotations: 
      Relational:DiscriminatorValue: P
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: PBase Abstract
    Properties: 
      ID (int) Required PK ReadOnlyAfterSave 0 0 0 -1 -1
      Discriminator (no field, string) Shadow Required ReadOnlyAfterSave RequiresValueGenerator 1 1 -1 0 -1
        Annotations: 
          ValueGeneratorFactory: System.Func`3[Microsoft.EntityFrameworkCore.Metadata.IProperty,Microsoft.EntityFrameworkCore.Metadata.IEntityType,Microsoft.EntityFrameworkCore.ValueGeneration.ValueGenerator]
      Stuff (string) 2 2 -1 -1 -1
    Keys: 
      ID PK
    Annotations: 
      Relational:DiscriminatorProperty: Discriminator
      Relational:DiscriminatorValue: PBase
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: Q Base: PBase
    Annotations: 
      Relational:DiscriminatorValue: Q
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: T Base: P
    Properties: 
      DID (no field, Nullable<int>) Shadow FK Index 3 3 1 1 -1
      FID (no field, Nullable<int>) Shadow FK Index 4 4 2 2 -1
      LID (no field, Nullable<int>) Shadow FK Index 5 5 3 3 0
      PID (no field, Nullable<int>) Shadow FK Index 6 6 4 4 -1
    Navigations: 
      D (<D>k__BackingField, Q) ToPrincipal Q 0 -1 5 -1 -1
      F (<F>k__BackingField, Q) ToPrincipal Q 1 -1 6 -1 -1
      P (<P>k__BackingField, P) ToPrincipal P 2 -1 7 -1 -1
    Foreign keys: 
      DID -> PBase.ID ToPrincipal: D
      FID -> PBase.ID ToPrincipal: F
      LID -> L.ID ToDependent: Ts
      PID -> PBase.ID ToPrincipal: P
    Annotations: 
      Relational:DiscriminatorValue: T
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
Annotations: 
  ProductVersion: 1.2.0-csproj
  SqlServer:ValueGenerationStrategy: IdentityColumn

@divega divega added this to the 1.2.0 milestone Nov 18, 2016
AndriySvyryd added a commit that referenced this issue Nov 30, 2016
Make the temporality of the client generated values depend on whether a value will be generated by the store.
Make DatabaseGeneratedOption.Identity attribute just set ValueGenerated to OnAdd on SQL Server.
Add a test relational provider so that the purely relational tests can use the correct conventions.

Part of #7010
Fixes #7049
AndriySvyryd added a commit that referenced this issue Nov 30, 2016
Make the temporality of the client generated values depend on whether a value will be generated by the store.
Make DatabaseGeneratedOption.Identity attribute just set ValueGenerated to OnAdd on SQL Server.
Add a test relational provider so that the purely relational tests can use the correct conventions.

Part of #7010
Fixes #7049
AndriySvyryd added a commit that referenced this issue Dec 7, 2016
…d, this disables client-side value generation for non-key properties that don't have a custom value generator.

Make DatabaseGeneratedOption.Identity attribute just set ValueGenerated to OnAdd on SQL Server
Update ValueGenerated using conventions
Make the temporality of the client generated values depend on whether a value will be generated by the store
Add a test relational provider so that the purely relational tests can use the correct conventions

Part of #7010
Fixes #7049
AndriySvyryd added a commit that referenced this issue Dec 7, 2016
…d, this disables client-side value generation for non-key properties that don't have a custom value generator.

Make DatabaseGeneratedOption.Identity attribute just set ValueGenerated to OnAdd on SQL Server
Update ValueGenerated using conventions
Make the temporality of the client generated values depend on whether a value will be generated by the store
Add a test relational provider so that the purely relational tests can use the correct conventions

Part of #7010
Fixes #7049
@HappyNomad
Copy link
Author

My workaround has been to rename my model's "ID" properties to "Id", so I thought the fix would be simply to add IgnoreCase or the like somewhere. Has this turned out to be more complicated?

@AndriySvyryd
Copy link
Member

@HappyNomad The issue is that we aren't always running the conventions. The fix I sent has problems though, so I'll send out a different one.

@AndriySvyryd AndriySvyryd removed their assignment Jan 9, 2017
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 9, 2017
@ajcvickers ajcvickers changed the title Exception says another instance has same key, but it doesn't Model configuration: Incorrect key discovery can result in exception saying another instance has same key, but it doesn't May 9, 2017
@divega divega added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. labels May 10, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

4 participants