试图将迁移后更新我的数据库时,我有一个错误。
这里是我的类加载迁移之前
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 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语句冲突与外键约束“FK_dbo.ProductFeatures_dbo.Products_ProductId”。 发生于数据库“CBL”,表“dbo.Products”的冲突,列“产品ID”
我能做些什么来解决这个问题,让我的迁移恢复正常?
解决这一问题的关键是要打破迁移到两个迁移。 首先,添加一个可空字段填写数据。 其次,使该领域所需的外键。
首先迁移
新的属性添加到您的类为可空类型(如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所实例指向同MyOtherEntity实例ID为1。
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
其他注意事项
- 这种技术适用于应用过程中应用迁移启动。
- 添加更加复杂的映射在SQL新列是可能的,但在这里没有说明。
我今天碰到这个问题来了。 下面是我如何处理它。 我确实有让我的FK属性为空的这是不是在我的情况下,一个大问题。
我做了我改变我的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。
当您尝试在已包含数据的表的非空列添加外键约束,它可以发生。 如果你的表中包含的数据将首先尝试将其删除,并重新尝试更新数据库。
简单的回答是 - 先增加一个新空列的产品编号,然后将现有的所有行一些默认值,然后设置列非空(如果你需要的),以便将来插入,加最后加上外键约束。
我写了一篇很长的博客文章对眼前这个完整的源代码,包括- http://nodogmablog.bryanhogan.net/2015/04/entity-framework-non-null-foreign-key-migration/
这是一个老问题,但目前还没有必要创建一个单独的迁移,并可以使用几个步骤来解决这个问题:
- 运行添加-迁移与所述实体的变化(新的不可为空的参考属性添加,产品编号在这种情况下)脚手架新的迁移类
- 修改新添加的迁移创建一个空列(可为空:真),而不是不可为空
- 下面AddColumn添加SQL命令设置列的值需要
- 下面添加AlterColumn命令,这将使列不为空如预期
在以上示例将如下所示:
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");
}