entity-framework - 使用 Code First 迁移添加外键

标签 entity-framework foreign-keys entity-framework-migrations

添加迁移后尝试更新我的数据库时出现错误。

这是我在添加迁移之前的类(class)

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命令,这是我得到的:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.ProductFeatures_dbo.Products_ProductId". The conflict occurred in database "CBL", table "dbo.Products", column 'ProductId'



我该怎么做才能解决这个问题并使我的迁移恢复正常?

最佳答案

解决这个问题的关键是把你的迁移分成两次迁移。首先,添加一个可为空的字段并填写数据。其次,使该字段成为必需的外键。

第一次迁移

  • 将新属性作为可空类型(例如 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
    

  • 其他注意事项
  • 此技术适用于在应用程序启动期间应用的迁移。
  • 可以为 SQL 中的新列添加更复杂的映射,但这里没有说明。
  • 关于entity-framework - 使用 Code First 迁移添加外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13650257/

    相关文章:

    entity-framework-5 - EF Code First 迁移导致 CA1701 和 CA1703

    c# - 无法在 mvc 5 项目中添加新模型和更新数据库?

    c# - Entity Framework : Recovered connectivity still yields 11001 error

    google-app-engine - Objectify - 如何声明外键?

    c# - 允许空外键 GUID

    mysql - Spring JPA OneToMany 重复条目 MySQLConstraint 违规错误

    python - 无法从 Django sqlite3 数据库中删除项目,错误为 "foreign key constraint failed"

    entity-framework - 如何删除种子方法中的所有数据?

    c# - 如何自定义身份模型以重命名 IdentityServer4 中的列并调整数据类型的大小

    mysql - 在 Visual Studio 2010 中将 MySQL 数据库与 Entity Framework 结合使用