30

Entity Framework 4.3CodeFirstを手動移行とSQLExpress2008で使用してプロジェクトを開始し、最近EF5(VS 2010)に更新したところ、外部キー制約などを変更すると、移行コードに「dbo」が追加されることに気付きました。テーブル名の先頭に、したがってそれが構築する外部キー名は、既存の制約に対して正しくありません(そして一般的に今では奇妙な名前に見えます)。

EF 4.3の元の移行スクリプト(ForeignKey( "Products"、t => t.Product_Id)に注意):

    CreateTable(
        "Products",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                ProductName = c.String(),
            })
        .PrimaryKey(t => t.Id);

    CreateTable(
        "KitComponents",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Component_Id = c.Int(),
                Product_Id = c.Int(),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("Products", t => t.Component_Id)
        .ForeignKey("Products", t => t.Product_Id)
        .Index(t => t.Component_Id)
        .Index(t => t.Product_Id);

生成された外部キー名:FK_KitComponents_Products_Product_Id FK_KitComponents_Products_Component_Id

次にEF5にアップグレードして外部キーを変更すると、移行コードは次のようになります(「KitComponents」と「Products」だけではなく、 「dbo.KitComponents」と「dbo.Products」に注意してください)。

DropForeignKey("dbo.KitComponents", "Product_Id", "dbo.Products");
DropIndex("dbo.KitComponents", new[] { "Product_Id" });

そして、更新データベースは次のメッセージで失敗します:' FK_dbo.KitComponents_dbo.Products_Product_Id 'は制約ではありません。制約を削除できませんでした。以前のエラーを参照してください。

したがって、EF5の時点で、制約の命名がFK_KitComponents_Products_Product_IdからFK_dbo.KitComponents_dbo.Products_Product_Id(dbo。プレフィックス付き)に変更されたようです。

EF5をEF4.3の場合と同じように動作させて、吐き出す新しい移行コードをすべて変更する必要がないようにするにはどうすればよいですか?

これが変更された理由とその対処法に関するリリースノートを見つけることができませんでした:(

4

4 に答える 4

32

CSharpMigrationCodeGeneratorクラスをサブクラス化することにより、生成されたコードをカスタマイズできます。

class MyCodeGenerator : CSharpMigrationCodeGenerator
{
    protected override void Generate(
        DropIndexOperation dropIndexOperation, IndentedTextWriter writer)
    {
        dropIndexOperation.Table = StripDbo(dropIndexOperation.Table);

        base.Generate(dropIndexOperation, writer);
    }

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

    private string StripDbo(string table)
    {
        if (table.StartsWith("dbo."))
        {
            return table.Substring(4);
        }

        return table;
    }
}

次に、移行構成クラスに設定します。

class Configuration : DbMigrationsConfiguration<MyContext>
{
    public Configuration()
    {
        CodeGenerator = new MyCodeGenerator();
    }
}
于 2012-08-21T18:34:28.620 に答える
5

自動移行の場合は、次のコードを使用します。

public class MyOwnMySqlMigrationSqlGenerator : MySqlMigrationSqlGenerator
{
    protected override MigrationStatement Generate(AddForeignKeyOperation addForeignKeyOperation)
    {
        addForeignKeyOperation.PrincipalTable = addForeignKeyOperation.PrincipalTable.Replace("dbo.", "");
        addForeignKeyOperation.DependentTable = addForeignKeyOperation.DependentTable.Replace("dbo.", "");
        MigrationStatement ms = base.Generate(addForeignKeyOperation);
        return ms;
    }
}

そしてそれを構成に設定します:

SetSqlGenerator("MySql.Data.MySqlClient", new MyOwnMySqlMigrationSqlGenerator());
于 2014-05-14T13:53:06.323 に答える
2

これは良い答えですが、「クイックフィックス」アプローチを探しているだけの場合は、これもあります。キーが基本クラスにある場合、EFMigrationsDropForeignKeyは失敗します。

パラメータprincipalNameとnameを含むDropForeignKeyオーバーロードを使用します。この場合は制約名を意味します。

于 2012-09-14T22:16:02.483 に答える
1

bricelamの答えを改善して、EF6でこれを試しました。スキーマをテーブル名の一部として保持し、FKまたはPK名からのみ削除するようにいくつかの変更を加えました

internal class MyCodeGenerator : CSharpMigrationCodeGenerator
{
    protected override void Generate(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
    {
        addForeignKeyOperation.Name = this.StripDbo(addForeignKeyOperation.Name, addForeignKeyOperation.DependentTable);
        addForeignKeyOperation.Name = this.StripDbo(addForeignKeyOperation.Name, addForeignKeyOperation.PrincipalTable);
        base.Generate(addForeignKeyOperation, writer);
    }

    protected override void Generate(AddPrimaryKeyOperation addPrimaryKeyOperation, IndentedTextWriter writer)
    {
        addPrimaryKeyOperation.Name = StripDbo(addPrimaryKeyOperation.Name, addPrimaryKeyOperation.Table);
        base.Generate(addPrimaryKeyOperation, writer);
    }

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

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

    private string StripDbo(string objectName, string tableName)
    {
        if (tableName.StartsWith("dbo."))
        {
            return objectName.Replace(tableName, tableName.Substring(4));
        }

        return objectName;
    }
}
于 2014-12-24T19:50:49.157 に答える