efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Add-Migration fails with "An item with the same key has already been added" when renaming entity

Open srmagura opened this issue 2 years ago • 13 comments

I made this change to my DbContext and now Add-Migration fails:

-        public DbSet<DbImport> Imports => Set<DbImport>();
+        public DbSet<DbPageImport> PageImports => Set<DbPageImport>();

In words: I renamed the DbImport entity class AND renamed the Imports table.

Include your code

I have tried to create a minimal reproduction of the issue but can't get the error to occur. If necessary, I can strip out everything from my real codebase until I have a small project that demonstrates the bug (but this would be a lot of work).

Both me and my coworker are able to consistently reproduce the bug on our real closed-source codebase. I am happy to send this codebase to any EF Core contributor as a private GitHub repo.

Include verbose output

Output from Add-Migration in Package Manager Console in Visual Studio 2022:

PM> add-migration TestMigration -Verbose
Using project 'Backend\Data\DataContext'.
Using startup project 'Backend\Functions\FunctionApp'.
Build started...
Build succeeded.
C:\Program Files\dotnet\dotnet.exe exec --depsfile C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\bin\Debug\net6.0\FunctionApp.deps.json --additionalprobingpath C:\Users\SamMa\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\bin\Debug\net6.0\FunctionApp.runtimeconfig.json C:\Users\SamMa\.nuget\packages\microsoft.entityframeworkcore.tools\6.0.2\tools\netcoreapp2.0\any\ef.dll migrations add TestMigration --json --verbose --no-color --prefix-output --assembly C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\bin\Debug\net6.0\DataContext.dll --project C:\Projects\System7\Slateplan\Backend\Data\DataContext\DataContext.csproj --startup-assembly C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\bin\Debug\net6.0\FunctionApp.dll --startup-project C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\FunctionApp.csproj --project-dir C:\Projects\System7\Slateplan\Backend\Data\DataContext\ --language C# --configuration Debug --working-dir C:\Projects\System7\Slateplan --root-namespace DataContext --nullable
Using assembly 'DataContext'.
Using startup assembly 'FunctionApp'.
Using application base 'C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp\bin\Debug\net6.0'.
Using working directory 'C:\Projects\System7\Slateplan\Backend\Functions\FunctionApp'.
Using root namespace 'DataContext'.
Using project directory 'C:\Projects\System7\Slateplan\Backend\Data\DataContext\'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'FunctionApp'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'AppDataContext'.
Using context 'AppDataContext'.
Finding design-time services referenced by assembly 'FunctionApp'...
Finding design-time services referenced by assembly 'DataContext'...
No referenced design-time services were found.
Finding design-time services for provider 'Microsoft.EntityFrameworkCore.SqlServer'...
Using design-time services from provider 'Microsoft.EntityFrameworkCore.SqlServer'.
Finding IDesignTimeServices implementations in assembly 'FunctionApp'...
No design-time services were found.
The index {'OrganizationId'} was not created on entity type 'DbComponentType' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'ComponentId'} was not created on entity type 'DbComponentVersion' as the properties are already covered by the index {'ComponentId', 'VersionName'}.
The index {'PageId'} was not created on entity type 'DbDesignerData' as the properties are already covered by the index {'PageId', 'Type'}.
The index {'OrganizationId'} was not created on entity type 'DbLogoSet' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'OrganizationId'} was not created on entity type 'DbProductFamily' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'ProductKitId'} was not created on entity type 'DbProductKitVersion' as the properties are already covered by the index {'ProductKitId', 'VersionName'}.
The index {'OrganizationId'} was not created on entity type 'DbProductPhoto' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'OrganizationId'} was not created on entity type 'DbProject' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'ProjectId'} was not created on entity type 'DbProjectPublication' as the properties are already covered by the index {'ProjectId', 'RevisionNumber'}.
The index {'OrganizationId'} was not created on entity type 'DbSymbol' as the properties are already covered by the index {'OrganizationId', 'Name'}.
The index {'OrganizationId'} was not created on entity type 'DbTermsDocument' as the properties are already covered by the index {'OrganizationId', 'Number'}.
The property 'DbComponentVersion.SellPrice#Money.DbComponentVersionId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbComponentVersion.Url#Url.DbComponentVersionId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbLogoSet.DarkLogo#DbFileRef.DbLogoSetId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbLogoSet.LightLogo#DbFileRef.DbLogoSetId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbPage.Pdf#DbFileRef.DbPageId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbPage.Thumbnail#DbFileRef.DbPageId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbPageImport.File#DbFileRef.DbPageImportId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbPageImport.PercentComplete#Percentage.DbPageImportId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbProductKitVersion.SellPrice#Money.DbProductKitVersionId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbProductPhoto.Photo#DbFileRef.DbProductPhotoId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbProject.Photo#DbFileRef.DbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbReport.File#DbFileRef.DbReportId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbReport.PercentComplete#Percentage.DbReportId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbTermsDocument.File#DbFileRef.DbTermsDocumentId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbUser.Email#EmailAddress.DbUserId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'DbProjectReportOptions.DbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'EncodedPassword.DbUserId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'PhoneNumber.CompanyContactInfoDbProjectReportOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'CompanyContactInfo.DbProjectReportOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'CompanyContactInfo.Email#EmailAddress.CompanyContactInfoDbProjectReportOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'CompanyContactInfo.Url#Url.CompanyContactInfoDbProjectReportOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'OrganizationShortName.DbOrganizationId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'PartialAddress.DbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'PersonName.DbUserId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'PostalCode.PartialAddressDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'ProjectBudgetOptions.DbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'ProjectBudgetOptions.CostAdjustment#Percentage.ProjectBudgetOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
The property 'ProjectBudgetOptions.DepositPercentage#Percentage.ProjectBudgetOptionsDbProjectId' was created in shadow state because there are no eligible CLR members with a matching name.
DetectChanges starting for 'AppDataContext'.
DetectChanges completed for 'AppDataContext'.
DetectChanges starting for 'AppDataContext'.
DetectChanges completed for 'AppDataContext'.
'AppDataContext' disposed.
System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
An item with the same key has already been added. Key: System.Object Item [System.String]

Include provider and version information

EF Core version: 6.0.2 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 6.0 Operating system: Windows 11 IDE: Visual Studio 2022 17.1.0

srmagura avatar Feb 24 '22 22:02 srmagura

Workaround

  1. Rename the entity class: DbImport -> DbPageImport.
  2. Add migration.
  3. Rename the DbSet property on the DbContext: Imports -> PageImports
  4. Add migration. (it works)

srmagura avatar Feb 24 '22 22:02 srmagura

@bricelam I think we might have seen this before.

ajcvickers avatar Feb 28 '22 20:02 ajcvickers

Looks like #26405, but that was supposed to be fixed in 6.0.2.

bricelam avatar Feb 28 '22 23:02 bricelam

@srmagura I think we're going to need a full repro for this.

ajcvickers avatar Mar 02 '22 11:03 ajcvickers

@ajcvickers No problem. Are you all right with me sending the full project (with repro instructions), or should I work on trimming out everything that is not relevant to the bug?

srmagura avatar Mar 02 '22 15:03 srmagura

@srmagura The latter is always preferred. Assuming there is a bug here, then that work will have to be done by someone, and it's often easier for the person who knows the code than it is for someone like me who has to figure out how everything in the project is organized and fits together.

ajcvickers avatar Mar 02 '22 17:03 ajcvickers

Sounds good, I will work on it. It may be about 2 weeks — I'll comment here when it is ready.

srmagura avatar Mar 02 '22 17:03 srmagura

@srmagura upgrading to 6.0.2 as per @bricelam above, fixed issue for me

glenkitchen avatar Mar 03 '22 06:03 glenkitchen

Minimal repro is done! https://github.com/srmagura/EFIssue27504 The README includes instructions for reproducing the bug. Thank you.

srmagura avatar Mar 12 '22 18:03 srmagura

@srmagura upgrading to 6.0.2 as per @bricelam above, fixed issue for me

Is it fixed on 6.0.2? I'm still getting it on 6.0.4

   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
An item with the same key has already been added. Key: System.Object Item [System.String]
Entity Framework Core .NET Command-line Tools
6.0.4

mjamro avatar May 02 '22 16:05 mjamro

@mjamro Make sure to update all EF packages, not just the tools

AndriySvyryd avatar May 06 '22 01:05 AndriySvyryd

Hello, I am getting same error, when I try to create migration after removing entity with owned entities. Version of all EFCore related nugets + tools: 6.0.7 In this example project EfMigrationIssueOwnedEntities.zip you can get error by using commands: When I try to add migration either by dotnet ef migrations add DroFoo or Add-Migration DropFoo in package manager console, i am getting same error:

Build started...
Build succeeded.
System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.De
[EfMigrationIssueOwnedEntities.zip](https://github.com/dotnet/efcore/files/9182842/EfMigrationIssueOwnedEntities.zip)
[EfMigrationIssueOwnedEntities.zip](https://github.com/dotnet/efcore/files/9182856/EfMigrationIssueOwnedEntities.zip)
sign.OperationExecutor.OperationBase.Execute(Action action)
An item with the same key has already been added. Key: System.Object Item [System.String]

There is workaround:

  1. Flatten entity: replace owned entities with direct properties. Column names and types remains same
  2. Create intermediate migration - it should be empty
  3. Remove entity and entity configuration
  4. Create migration - it should contain drop table command
  5. You can remove intermediate migration

eMTeeSK avatar Jul 25 '22 15:07 eMTeeSK

I just got this error after doing major code refactoring. The scenario is There was AgentBooking Entity. Now the business decide to add OnlineBooking, Then I need to refactor AgentBooking & OnlineBooking to inherit from Abstract Booking Entity and rename some columns.

This error appear, if I remove all previous migrations & DbContextModelSnapshot, then recreate one it will be successful. But there is no way to run this migration in production environment.

Is there anyway to debug migrations tools? I need to find out where is the problem. Key: System.Object Item [System.String] is kinda unhelpful at all.

huang-tianwen avatar Sep 15 '22 10:09 huang-tianwen

Got the same when adding a migration that removes two completely independent DbSets (flat tables no relationships etc).

carlosrfernandez avatar Oct 11 '22 15:10 carlosrfernandez

I got the same error, I'm using entities with owned entities. If I remove the DbSets the generated migrations are empty. If I remove the DbSets and fluent-maps, it throw the error.

nev-21 avatar Oct 27 '22 14:10 nev-21

Seeing the same in 6.0.1 caused by removing an entity (and the associated DbSet on the DbContext) that had an owned entity.

I was able to work around this by removing the representation of said entity in the snapshot, scaffolding an empty migration and populating the respective Up and Down from the initial migration that was already present.

System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
An item with the same key has already been added. Key: System.Object Item [System.String]

wojtek-viirtue avatar Nov 15 '22 03:11 wojtek-viirtue

+1.. In my use case I'm trying to write my own version of EnsureCreatedAsync using either the IMigrationsAssembly.ModelSnapshot.Model or migration.TargetModel, so I can then test further migrations;

var migrations = db.GetService<IMigrationsAssembly>();
var init = db.GetService<IModelRuntimeInitializer>();
var model = migrations.ModelSnapshot.Model;
if (model is IMutableModel m)
    model = m.FinalizeModel();
model = init.Initialize(model);
var relational = model.GetRelationalModel();
var diffOperations = modelDiffer.GetDifferences(null, relational);

However at https://github.com/dotnet/efcore/blob/3f82c2b0af132b7019f6bd8b32c2709469b0ffae/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs#L794 linkingNavigationProperty is always the same PropertyInfo; Dictionary<string,object>.Item[string]. Leading to the same duplicate key exception as seen above.

MigrationsModelDiffer.GetSortedProperties is clearly assuming that all PropertyInfo's are unique. Which is an invalid assumption.

Perhaps this dummy PropertyInfo should not be set in the relational model, or it should be treated the same as a null value in the loop linked above.

lakeman avatar Nov 25 '22 01:11 lakeman

Adding an explicit test for Dictionary<string,object> should fix the problem;

foreach (var linkingForeignKey in table.GetReferencingRowInternalForeignKeys(entityType))
{
    var linkingNavigationProperty = linkingForeignKey.PrincipalToDependent?.PropertyInfo;
    var properties = GetSortedProperties(linkingForeignKey.DeclaringEntityType, table).ToList();
    if (linkingNavigationProperty == null
+       || linkingNavigationProperty.DeclaringType == typeof(Dictionary<string,object>))
    {
        leastPriorityProperties.AddRange(properties);
        continue;
    }

Or should that be something like;

foreach (var linkingForeignKey in table.GetReferencingRowInternalForeignKeys(entityType))
{
    var properties = GetSortedProperties(linkingForeignKey.DeclaringEntityType, table).ToList();
    var linkingNavigation = linkingForeignKey.PrincipalToDependent;
    if (linkingNavigation?.PropertyInfo == null
        || linkingNavigation.IsIndexerProperty()
        || linkingNavigation.IsShadowProperty())
    {
        leastPriorityProperties.AddRange(properties);
        continue;
    }
    var linkingNavigationProperty = linkingNavigation.PropertyInfo;

    groups.Add(linkingNavigationProperty, properties);

lakeman avatar Nov 25 '22 03:11 lakeman

Hi there! Anything happening on this bug? I just did a big refactor on my project, both dropping (empty) and adding tables, incl. owned-properties. I'm using .net6 and tried EF Core Tools 6.0.12 and now even 7.0.1 (still using .net6).

System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

This should probably rank as one of the most useless error messages I have seen, so I really don't know what to do. Considering recreating the entire database right now as I was just suppose to clean up and publish this...

Best regards,

HugCoder avatar Dec 26 '22 19:12 HugCoder

This just hit us on a large project that has recently been upgraded to .net7 and EF Core 7.01. We are refactoring to remove all OwnedEntities. We removed one, successfully added a migration, then spent hours factoring out dozens of other owned entites. Then we tried to add another migration and this error hit.

The error is so vague it gives no clue how to proceed.

System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

amosolson avatar Dec 30 '22 16:12 amosolson

This bug is triggered while sorting columns for a create table operation. When two classes map to the same table, via a navigation property that is also an "indexer property".

When loading a model snapshot, all properties are indexer properties. So this bug is most likely triggered when the model differ can't locate a matching table in your new model, and needs to generate a create table operation for the Down script.

You could try scaffolding your schema in a blank project. Adding a migration. Then moving the contents of the generated model snapshot to your code first project. Avoiding any shared tables in the model snapshot.

lakeman avatar Dec 30 '22 22:12 lakeman

The one line diff I posted above should avoid the exception. But a better fix would sort columns without using PropertyInfo as a dictionary key.

For my own project I replaced the model differ service to test the one line code change. However, overriding the implementation of MigrationsModelDiffer.GetSortedProperties involved copying huge slabs of internal code. Not really viable as a workaround for production code. Though you only need this fix when generating migrations, you don't need to deploy any of this code to production.

lakeman avatar Dec 30 '22 22:12 lakeman

This just hit us on a large project that has recently been upgraded to .net7 and EF Core 7.01. We are refactoring to remove all OwnedEntities. We removed one, successfully added a migration, then spent hours factoring out dozens of other owned entites. Then we tried to add another migration and this error hit.

The error is so vague it gives no clue how to proceed.

System.ArgumentException: An item with the same key has already been added. Key: System.Object Item [System.String]
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedProperties(IEntityType entityType, ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetSortedColumns(ITable table)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Add(ITable target, DiffContext diffContext)+MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
   at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IRelationalModel source, IRelationalModel target)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

It happened to me too after upgrade following packages:

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.1" />

Now I cannot create any Migration because of this error, so I had to downgrade these packages.

pklejnowski avatar Jan 04 '23 15:01 pklejnowski

My error, and how I resolved it

I encountered the same error message when using Entity Framework Core .NET Command-line Tools 7.0.1 in a project that depended on versions 6.0.9 of each of the various Entity Framework Core packages. This is an oversimplification of my model, but it shows all the parts that were relevant to solving my error.

Code

DbContext snippet

public DbSet<Foo> Foos { get; set; } = null!;

protected override void OnModelCreating(ModelBuilder mb)
{
    mb.Entity<Foo>().OwnsOne(f => f.Prop1);
    mb.Entity<Foo>().OwnsOne(f => f.Prop2);
}

Foo snippet

[Key]
public int FooId { get; set; }
public Bar Prop1 { get; set; } = new();
public Bar Prop2 { get; set; } = new();

Bar snippet

public string Baz { get; set; } = "";
public string Qux { get; set; } = "";

The problem

Removing the Foo class and any references to it and then running dotnet ef migrations add MigrationName resulted in the same error message as reported by others in this thread.

How I resolved it

  1. remove the navigation properties Prop1 and Prop2 from Foo
  2. add a new migration
  3. delete the DbSet<Foo> property from the DbContext
  4. add a new migration

Conclusion

I am relatively new to Entity Framework Core, so I cannot diagnose what initially caused this error, but I assume it has something to do with deleting entities that have owned entities attached.

Matt-Crow avatar Jan 05 '23 00:01 Matt-Crow

@AndriySvyryd I just tested the latest dotnet ef cli, that I think should contain the fixe https://github.com/dotnet/efcore/pull/29981, and I still get the error.

PS C:\Users\apaquette> dotnet tool uninstall -g dotnet-ef
L'outil 'dotnet-ef' (version '7.0.2') a été désinstallé.
PS C:\Users\apaquette> dotnet tool install -g dotnet-ef --version 8.0.0-* --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json
Vous pouvez appeler l'outil à l'aide de la commande suivante : dotnet-ef
L'outil 'dotnet-ef' (version '8.0.0-alpha.1.23066.4') a été installé correctement.

I have a table that contains owned types and this table is not registered with a DbSet<> but only by a IEntityTypeConfiguration<>. When removing the configuration I get the same error as everybody.

Was it supposed to work or is it the same message for an other error? Thank you!

adampaquette avatar Jan 17 '23 20:01 adampaquette

@adampaquette This fix is not included in 7.0.2. Check the milestone on the issue.

ajcvickers avatar Jan 17 '23 20:01 ajcvickers

@ajcvickers This is why I installed 8.0.0-alpha.1.23066.4. Hum

adampaquette avatar Jan 17 '23 20:01 adampaquette

Ah sorry, missed that. The version of the CLI tool doesn't usually matter. Make sure your project is using the latest daily build packages.

ajcvickers avatar Jan 17 '23 20:01 ajcvickers

@ajcvickers We're also running into this issue when changing (and renaming) a 1:n entity to an owned entity. The workaround of ignoring unfortunately does not work. It appears that there are no pre-releases of EF 7.0.3 on the NuGet feed, is that observation correct?

edit: Unfortunately EF 8.0.0 alpha has the same issue. Happy to send the solution.

Sebazzz avatar Jan 19 '23 09:01 Sebazzz

@Sebazzz Please open a new issue and attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

ajcvickers avatar Jan 19 '23 11:01 ajcvickers