将使用代码首先迁移外键(adding a foreign key with Code First m

2019-07-04 08:26发布

试图将迁移后更新我的数据库时,我有一个错误。

这里是我的类加载迁移之前

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”

我能做些什么来解决这个问题,让我的迁移恢复正常?

Answer 1:

解决这一问题的关键是要打破迁移到两个迁移。 首先,添加一个可空字段填写数据。 其次,使该领域所需的外键。

首先迁移

  1. 新的属性添加到您的类为可空类型(如int?)

     public class MyOtherEntity { public int Id { get; set; } } public class MyEntity { ... // New reference to MyOtherEntity public int? MyOtherEntityId { get; set; } ... } 
  2. 创建一个迁移。 注:迁移名字并不重要,但像“AddBlogPosts1”可以很容易地阅读。

     > add-migration AddMyEntityMyOtherEntity1 
  3. 这应该脚手架迁移,看起来像这样:

     public partial class AddMyTableNewProperty1 : DbMigration { public override void Up() { AddColumn("dbo.MyEntity", "MyOtherEntityId", c => c.Int()); } public override void Down() { DropColumn("dbo.MyEntity", "MyOtherEntityId"); } } 
  4. 现在,手动编辑生成迁移到新字段添加的默认值。 最简单的情况是,当默认值是不变的。 如果需要,可以在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"); } } 
  5. 更新数据库

     > update-database 

第二迁移

  1. 回到你的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; } ... } 
  2. 创建另一个迁移

     > add-migration AddMyEntityMyOtherEntity2 
  3. 这应该创建一个类似下面的迁移:

     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()); } } 
  4. 更新数据库

     > update-database 

其他注意事项

  1. 这种技术适用于应用过程中应用迁移启动。
  2. 添加更加复杂的映射在SQL新列是可能的,但在这里没有说明。


Answer 2:

我今天碰到这个问题来了。 下面是我如何处理它。 我确实有让我的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。



Answer 3:

当您尝试在已包含数据的表的非空列添加外键约束,它可以发生。 如果你的表中包含的数据将首先尝试将其删除,并重新尝试更新数据库。



Answer 4:

简单的回答是 - 先增加一个新空列的产品编号,然后将现有的所有行一些默认值,然后设置列非空(如果你需要的),以便将来插入,加最后加上外键约束。

我写了一篇很长的博客文章对眼前这个完整的源代码,包括- http://nodogmablog.bryanhogan.net/2015/04/entity-framework-non-null-foreign-key-migration/



Answer 5:

这是一个老问题,但目前还没有必要创建一个单独的迁移,并可以使用几个步骤来解决这个问题:

  1. 运行添加-迁移与所述实体的变化(新的不可为空的参考属性添加,产品编号在这种情况下)脚手架新的迁移类
  2. 修改新添加的迁移创建一个空列(可为空:真),而不是不可为空
  3. 下面AddColumn添加SQL命令设置列的值需要
  4. 下面添加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");
    }


文章来源: adding a foreign key with Code First migration