移行を追加した後でデータベースを更新しようとすると、エラーが発生します。
これは移行前の私のクラスです
public class Product
{
public Product() { }
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool Istaxable { get; set; }
public string DefaultImage { get; set; }
public IList<Feature> Features { get; set; }
public IList<Descriptor> Descriptors { get; set; }
public IList<Image> Images { get; set; }
public IList<Category> Categories { get; set; }
}
public class Feature
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
次に、Featureクラスに外部キーを追加し、クラスを次のようにリファクタリングします。
public class Product
{
public Product() { }
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool Istaxable { get; set; }
public string DefaultImage { get; set; }
public IList<Feature> Features { get; set; }
public IList<Descriptor> Descriptors { get; set; }
public IList<Image> Images { get; set; }
public IList<Category> Categories { get; set; }
}
public class Feature
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string VideoLink { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
Add-Migration
コマンドを使用して移行を追加しました。私はUpdate-Database
コマンドを追加しました、そしてここに私が得たものがあります:
ALTER TABLEステートメントがFOREIGN KEY制約「FK_dbo.ProductFeatures_dbo.Products_ProductId」と競合しました。データベース「CBL」、テーブル「dbo.Products」、列「ProductId」で競合が発生しました
この問題を解決して、移行を通常の状態に戻すにはどうすればよいですか?
この問題を解決する鍵は、移行を2つの移行に分割することです。最初に、null許容フィールドを追加し、データを入力します。次に、フィールドを必須の外部キーにします。
新しいプロパティをnull許容型としてクラスに追加します(例:int?)
public class MyOtherEntity
{
public int Id { get; set; }
}
public class MyEntity
{
...
// New reference to MyOtherEntity
public int? MyOtherEntityId { get; set; }
...
}
移行を作成します。注:移行名は重要ではありませんが、「AddBlogPosts1」のようなものを使用すると読みやすくなります。
> add-migration AddMyEntityMyOtherEntity1
これは、次のような移行の足場になるはずです。
public partial class AddMyTableNewProperty1 : DbMigration
{
public override void Up()
{
AddColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int());
}
public override void Down()
{
DropColumn("dbo.MyEntity", "MyOtherEntityId");
}
}
次に、生成されたマイグレーションを手動で編集して、新しいフィールドのデフォルト値を追加します。最も簡単なケースは、デフォルト値が不変である場合です。必要に応じて、SQLにロジックを追加できます。この例では、すべてのMyEntityインスタンスがID 1の同じMyOtherEntityインスタンスを指していると想定しています。
public partial class AddMyTableNewProperty1 : DbMigration
{
public override void Up()
{
AddColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int());
// ADD THIS BY HAND
Sql(@"UPDATE dbo.MyEntity SET MyOtherEntityId = 1
where MyOtherEntity IS NULL");
}
public override void Down()
{
DropColumn("dbo.MyEntity", "MyOtherEntityId");
}
}
データベースを更新する
> update-database
MyEntityクラスに戻り、必須の外部キーを表すように新しいプロパティを変更します。
public class MyEntity
{
...
// Change the int? to int to make it mandatory
public int MyOtherEntityId { get; set; }
// Create a reference to the other entity
public virtual MyOtherEntity MyOtherEntity { get; set; }
...
}
別の移行を作成する
> add-migration AddMyEntityMyOtherEntity2
これにより、次のような移行が作成されます。
public partial class AddMyEntityMyOtherEntity2: DbMigration
{
public override void Up()
{
AlterColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int(nullable: false));
CreateIndex("dbo.MyEntity", "MyOtherEntityId");
AddForeignKey("dbo.MyEntity", "MyOtherEntityId", "dbo.MyOtherEntity", "Id");
}
public override void Down()
{
DropForeignKey("dbo.MyEntity", "MyOtherEntityId", "dbo.MyOtherEntity");
DropIndex("dbo.MyEntity", new[] { "MyOtherEntityId" });
AlterColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int());
}
}
データベースを更新する
> update-database
今日、この問題に遭遇しました。これが私がそれをどのように扱ったかです。私の場合、FKプロパティをnullにできるようにする必要がありましたが、これは大した問題ではありませんでした。
POCOに変更を加え、移行を生成してから、以下を移行に追加しました。
public partial class LineItemProductionHistory_v4 : DbMigration
{
public override void Up()
{
AddColumn("LineItemProductionHistories","TempLineItemId",c=>c.Int());
Sql("Update LineItemProductionHistories Set TempLineItemId = LineItem_Id");
.
. Generated code
.
Sql("Update LineItemProductionHistories Set LineItemId = TempLineItemId");
DropColumn("LineItemProductionHistories", "TempLineItemId");
}
}
私は一時的にすべての外部キーを保存し、移行に追加/ドロップを行わせてから、新しく作成されたFKに外部キーを戻します。
簡単な答えは-最初にProductIdにnull可能な列を追加し、次に既存のすべての行にデフォルト値を設定してから、将来の挿入のために列をnull以外に設定し(必要な場合)、最後に外部キー制約を追加します。
私はこれについて、完全なソースコードを含めて長いブログ投稿を書いた- http://nodogmablog.bryanhogan.net/2015/04/entity-framework-non-null-foreign-key-migration/
これは、すでにデータが含まれているテーブルのnull不可の列に外部キー制約を追加しようとしたときに発生する可能性があります。テーブルにデータが含まれている場合は、まずそれらを削除してから、データベースの更新を再試行してください。
これは古い問題ですが、現在、個別の移行を作成する必要はなく、この問題はいくつかの手順で解決できます。
上記の例では、次のようになります。
public override void Up()
{
AddColumn("dbo.ProductFeatures", "ProductId", c => c.Int(nullable: true));
Sql("UPDATE [dbo].[ProductFeatures] SET ProductId = (SELECT TOP 1 [Id] FROM [dbo].[Products])");
AlterColumn("dbo.ProductFeatures", "ProductId", c => c.Int(nullable: false));
CreateIndex("dbo.ProductFeatures", "ProductId");
AddForeignKey("dbo.ProductFeatures", "ProductId", "dbo.Products", "Id");
}