Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Code-First Migrations - Cannot drop constraint because it doesn't exist (naming convention from 4.3 to 5.0)

Was previously using EF 4.3 and upon upgrading to 5.0 I find out the Indexes, FK constraints, and PK constraints all have had their naming conventions changed to include dbo (eg. PK_Users has now become PK_dbo.Users)

Now anytime I make a change to the model and it needs to change a table that has these in it, it always says it can't drop constraint because it can't find it.

I just want it so that when it tries to drop a constraint/index/key it first checks to see if the pre-5.0 naming one exists and if so drop it, but still re-create it using the new 5.0 naming conventions.

The naming conventions changed like so from 4.3 to 5.0:

Primary Key/Indexes

Old: PK_Users                    New: PK_dbo.Users

Foreign Keys

Old: FK_Users_Roles_Role_Id      New: FK_dbo.Users_dbo.Roles_Role_Id               

Note: I CANNOT simply have EF regenerate all the tables, I have production data in this database. I also don't want to have to manually do this for every table using custom migrations.

Edit: I found a similar question How can I stop Entity Framework 5 migrations adding dbo. into key names? but this guy just wanted ignore 5.0 conventions and stick with 4.3, and it only dealt with table renaming. I'd prefer not to do that as subsequent versions of EF may cause more changes that would affect this code and just be a hassle down the line.

I tried doing something in the same vein as the answer posted:

public class CodeMigrator : CSharpMigrationCodeGenerator
{
    protected override void Generate(
        DropIndexOperation dropIndexOperation, IndentedTextWriter writer)
    {
        dropIndexOperation.Name = StripDbo(dropIndexOperation.Name);
        base.Generate(dropIndexOperation, writer);
    }

    protected override void Generate(DropForeignKeyOperation dropForeignKeyOperation, IndentedTextWriter writer)
    {
        dropForeignKeyOperation.Name = StripDbo(dropForeignKeyOperation.Name);
        base.Generate(dropForeignKeyOperation, writer);
    }

    protected override void Generate(DropPrimaryKeyOperation dropPrimaryKeyOperation, IndentedTextWriter writer)
    {
        dropPrimaryKeyOperation.Name = StripDbo(dropPrimaryKeyOperation.Name);
        base.Generate(dropPrimaryKeyOperation, writer);
    }

    // TODO: Override other Generate overloads that involve table names

    private string StripDbo(string name)
    {
        return name.Replace("dbo.", "");
    }
}

And adding it to the config:

public Configuration()
    {
        CodeGenerator = new CodeMigrator();
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;

    }

However the error still hits:

dbo.Users_dbo.Departments_Department_Id' is not a constraint. Could not drop constraint. See previous errors.

I actually tried override every single member in the CSharpMigrationCodeGenerator and setting a breakpoint on the return statement, and none of them hit. So it appears my custom generator never gets used, not sure what I am missing with that.

like image 455
SventoryMang Avatar asked Jun 21 '13 18:06

SventoryMang


1 Answers

I figured out the answer and it's similar to the answer in the question I linked to in my question. The problem overriding CSharpCodeGenerator is only used in custom migrations.

To override the automatic migrations you need to override the SqlServerMigrationSqlGenerator class and call SetSqlGenerator() in the Migration.Configuration constructor:

public class SqlMigrator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(DropForeignKeyOperation dropForeignKeyOperation)
    {
        dropForeignKeyOperation.Name = StripDbo(dropForeignKeyOperation.Name);
        base.Generate(dropForeignKeyOperation);
    }

    protected override void Generate(DropIndexOperation dropIndexOperation)
    {
        dropIndexOperation.Name = StripDbo(dropIndexOperation.Name);
        base.Generate(dropIndexOperation);
    }

    protected override void Generate(DropPrimaryKeyOperation dropPrimaryKeyOperation)
    {
        dropPrimaryKeyOperation.Name = StripDbo(dropPrimaryKeyOperation.Name);
        base.Generate(dropPrimaryKeyOperation);
    }

    private string StripDbo(string name)
    {
        return name.Replace("dbo.", "");
    }
}

And the migration config:

public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;
        SetSqlGenerator("System.Data.SqlClient", new SqlMigrator());
    }
like image 84
SventoryMang Avatar answered Oct 06 '22 00:10

SventoryMang