13

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.

Community
  • 1
  • 1
SventoryMang
  • 10,275
  • 15
  • 70
  • 113
  • did you try `-IngoreChanges`, it might (though not sure) be able to help - [-IngoreChanges](http://stackoverflow.com/a/9623319/417747). That would scafold your existing db 'as is' - but then you need to see what happens, it might work w/ existing naming. You might also need to manually adjust your migrations scripts (####.cs files) where/when needed. It'd probably 'hit a wall' at some point - I don't think you can run with old convention forever. Ignoring convention is not a bad idea to me, if possible. Let me know. – NSGaga-mostly-inactive Jun 21 '13 at 20:06
  • I don't want to ignore changes, I did make changes that need to be run, it's just that in the process of doing that, it tries to make a change with something that doesn't exist because it's looking for it via the new convention. I don't want to ignore convention or stick with the old one. I just need to be able to tell it how to find the thing its looking for, then behave like normal. I thought I could do this by changing the `Name` in the `MigrationOperations` to remove the dbo. references, but it doesn't appear to be running. – SventoryMang Jun 21 '13 at 20:13
  • I think I understand what you're trying to do - but you can't do 'exactly' what you want IMO, so you need the next best thing. Only starting EF6 you get a full control over conventions, creating custom ones etc. EF6 is already available (with full source), it's in beta still - but not for long - so maybe that's your option then (with custom conventions - I had a post with that if needed). And it's not exactly 'ignoring changes' - you ignore first the 'old state', so it can 'swallow' what you had before (you might need to go back to a code before). Then you apply the changes, and adjust mig. cs – NSGaga-mostly-inactive Jun 21 '13 at 20:26
  • So I would need to do a custom migration? Argh this is so frustrating why would MS make it so un-user friendly to upgrade versions of EF. – SventoryMang Jun 21 '13 at 20:41
  • In the answer I linked that person was using EF5, and looking through the decompiled code I see class DbMigrator called the Config's CodeGenerator.Generate in several places, including the Scaffold method, but I can't see where that is being called. Is this not working because I am not writing my own migration class like in the answer linked above? – SventoryMang Jun 21 '13 at 21:10
  • no that's not the case I think - calling DbMigrator directly - or via MigrateToLatest... or via PS console - it's the same. Important bit is how your migration ####... cs file looks like - and naming/conventions - you can't do much about it. EF/CF changed a lot, 4.* versions were first stable enough - and 5 is IMO the first real deal, that's why you have issues, lot of changes, but that's good - compatibility suffers :) – NSGaga-mostly-inactive Jun 21 '13 at 21:38
  • it's a very specific, custom case you have - what I'd do probably - is to generate the full migration script - like for empty Db - based on your current code (or best on your latest code that matches old db you have). You can do that by connecting to non-existing, empty Db. Then - create SQL script by doing update with script option. That creates the Db it expects to have under new migration conventions. Then go to Db (try this not on a live one but backup copy first, to see how, what), and 'adjust' indexes etc. - according to script. That means you'd need to drop/recreate. Try then again. – NSGaga-mostly-inactive Jun 21 '13 at 21:43

1 Answers1

6

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());
    }
SventoryMang
  • 10,275
  • 15
  • 70
  • 113