Entity Framework 4.3 CodeFirstを手動移行とSQLExpress 2008で使用してプロジェクトを開始し、最近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にアップグレードして外部キーを変更すると、移行コードは次のようになります( "dbo.KitComponents"および "dbo.Products"のようになります。 "KitComponents"および "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の場合と同じように動作させて、吐き出す新しい移行コードをすべて変更する必要がないようにするにはどうすればよいですか?
これが変更された理由とその対処法に関するリリースノートを見つけることができませんでした:(
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();
}
}
自動移行の場合は、次のコードを使用します。
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());
これは良い答えですが、「クイックフィックス」アプローチを探しているだけなら、これもあります キーが基本クラスにある場合、EF Migrations DropForeignKeyは失敗します
パラメータprincipalNameとnameを含むDropForeignKeyオーバーロードを使用します。この場合は制約名を意味します。
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;
}
}