简体   繁体   中英

System.InvalidOperationException on EF6 AssociationType Many-To-Many Table

I'm using EF6 Migrations Code First Conventions to rename all of my tables, properties, schemas, etc to fit our internal DB conventions. The Convention renames all of the fields and table names properly, compiles, and scaffolds as expected. However, when I go to update database, I get the following error:

System.InvalidOperationException: Sequence contains no matching element
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
   at System.Data.Entity.Migrations.DbMigrator.FillInForeignKeyOperations(IEnumerable`1 operations, XDocument targetModel)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, VersionedModel targetModel, IEnumerable`1 operations, IEnumerable`1 systemOperations, Boolean downgrading, Boolean auto)
   at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
   at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
   at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
   at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
   at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Sequence contains no matching element

Here is the Migration Code for the table that's causing the issue. I've validated that PK's are correct, the ForeignKey tables exist and the types are correct, the indexes point to the right fields, etc. I'm all out of ideas here.

CreateTable(
            "cw.map_cw_service_cw_immunization",
            c => new
                {
                    cw_service_id = c.String(nullable: false, maxLength: 36),
                    cw_immunization_id = c.String(nullable: false, maxLength: 36),
                })
            .PrimaryKey(t => new { t.cw_service_id, t.cw_immunization_id })
            .ForeignKey("cw.careware_services", t => t.cw_service_id, cascadeDelete: true)
            .ForeignKey("cw.careware_immunizations", t => t.cw_immunization_id, cascadeDelete: true)
            .Index(t => t.cw_service_id, name: "IX_CarewareService_Id")
            .Index(t => t.cw_immunization_id, name: "IX_CarewareImmunization_Id");

    }

UPDATE: I've narrowed the issue down to a foreign key problem. If I comment out the two foreign key extension methods, the database updates as expected. However, obviously that isn't a valid workaround as now the table has no FK constraints.

I did some digging based on the error stack and found the method below in the EntityFramework source. The error was caused by a Single() not returning a value. There is only one .Single() operation that doesn't return default, so that's obviously the culprit. That operations returns the single EntityTypeElement that matches the EntitySetName (since they're supposed to be unique). Long story short, I realize that somewhere in my code I must be accidentally changing the EntitySet.Name value instead of the EntitySet.Table value. Lo and behold, that was the culprit. I changed the line of code and it works just fine.

TL;DR; - Always check to make sure you're setting the EntitySet.Table value and not changing the EntitySet.Name value in your convetions.

private void FillInForeignKeyOperations(IEnumerable<MigrationOperation> operations, XDocument targetModel)
{
    DebugCheck.NotNull(operations);
    DebugCheck.NotNull(targetModel);

    foreach (var foreignKeyOperation
        in operations.OfType<AddForeignKeyOperation>()
                     .Where(fk => fk.PrincipalTable != null && !fk.PrincipalColumns.Any()))
    {
        var principalTable = GetStandardizedTableName(foreignKeyOperation.PrincipalTable);
        var entitySetName
            = (from es in targetModel.Descendants(EdmXNames.Ssdl.EntitySetNames)
               where _modelDiffer.GetQualifiedTableName(es.TableAttribute(), es.SchemaAttribute())
                                 .EqualsIgnoreCase(principalTable)
               select es.NameAttribute()).SingleOrDefault();

        if (entitySetName != null) //ERROR SOURCE IS BELOW
        {
            var entityTypeElement
                = targetModel.Descendants(EdmXNames.Ssdl.EntityTypeNames)
                             .Single(et => et.NameAttribute().EqualsIgnoreCase(entitySetName)); 

            entityTypeElement
                .Descendants(EdmXNames.Ssdl.PropertyRefNames).Each(
                    pr => foreignKeyOperation.PrincipalColumns.Add(pr.NameAttribute()));
        }
        else
        {
            // try and find the table in the current list of ops
            var table
                = operations
                    .OfType<CreateTableOperation>()
                    .SingleOrDefault(ct => GetStandardizedTableName(ct.Name).EqualsIgnoreCase(principalTable));

            if ((table != null)
                && (table.PrimaryKey != null))
            {
                table.PrimaryKey.Columns.Each(c => foreignKeyOperation.PrincipalColumns.Add(c));
            }
            else
            {
                throw Error.PartialFkOperation(
                    foreignKeyOperation.DependentTable, foreignKeyOperation.DependentColumns.Join());
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM