如何将新外键从新表添加到现有记录

时间:2018-03-12 18:08:09

标签: c# entity-framework tsql

使用C#MVC和Entity Framework v6.2.0

我有一个现有的模型,Caller

public class Caller
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public string FirstName { get; set; }
}

我创建了一个新模型LanguageChoice

public class LanguageChoice
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public string Name { get; set; }
}

我想将此新LanguageChoice添加到Caller

public class Caller
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public string FirstName { get; set; }

    public Guid LanguageChoice_Id { get; set; } // <----

    [ForeignKey("LanguageChoice_Id")]
    public LanguageChoice LanguageChoice { get; set; } // <----
}

我这样做是因为它在我的ViewModel中会是IEnumerable<SelectListItem>

在我的数据库中,我有Caller条记录:

╔═════════════════════╦═══════════╗
║         Id          ║ FirstName ║
╠═════════════════════╬═══════════╣
║ caller_guid_value_1 ║ Ryan      ║
║ caller_guid_value_2 ║ John      ║
╚═════════════════════╩═══════════╝

当我添加LanguageChoice时,预期的结果将是:

╔═════════════════════╦═══════════╦═════════════════════════════╗
║         Id          ║ FirstName ║      LanguageChoice_Id      ║
╠═════════════════════╬═══════════╬═════════════════════════════╣
║ caller_guid_value_1 ║ Ryan      ║ languageChoice_guid_value_1 ║
║ caller_guid_value_2 ║ John      ║ languageChoice_guid_value_1 ║
╚═════════════════════╩═══════════╩═════════════════════════════╝

这是我的迁移:

public partial class AddCallerLanguageChoice : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.LanguageChoices",
            c => new
                {
                    Id = c.Guid(nullable: false, identity: true),
                    Name = c.String(nullable: false, maxLength: 50),
                })
            .PrimaryKey(t => t.Id);

        AddColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid(nullable: false));
        CreateIndex("dbo.Callers", "LanguageChoice_Id");
        AddForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices", "Id", cascadeDelete: true);
    }

    public override void Down()
    {
        DropForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices");
        DropIndex("dbo.Callers", new[] { "LanguageChoice_Id" });
        DropColumn("dbo.Callers", "LanguageChoice_Id");
        DropTable("dbo.LanguageChoices");
    }
}

这让我错误:

  

ALTER TABLE语句与FOREIGN KEY约束冲突&#34; FK_dbo.Callers_dbo.LanguageChoices_LanguageChoice_Id&#34;。冲突发生在数据库&#34; aspnet-My Web App-20171030040324&#34;,table&#34; dbo.LanguageChoices&#34;,column&#39; Id&#39;。

无论如何都要这样做,或者我应该继续前进,让LanguageChoice_Id可以为空?

<小时/> 类似的问题来自4年前:Entity Framework The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

  • 4岁,从那时起可能发生了一些变化
  • 他们使用int ID为Ids,我使用Guid,因此我无法提前猜测/假设Id值
  • 我想避免创建一个LanguageChoice_Id可以为空的迁移,然后是一个更新记录的种子方法,然后是另一个使LanguageChoice_Id不可为空的迁移,因为当推送它们时会破坏迁移到Azure,因为种子方法最后运行。 (参见Ari Roth对RicklsWright的评论&#39;回答)

<小时/> 更新:

关注@henoc salinas&#39;更新的答案我来到这个有效的单一迁移文件。

Henoc的回答是接受的答案,这只是为了展示我最终得到的结果,不同之处在于我在此处插入了表值并使用非更新了Caller的空值临时值:

        public override void Up()
    {
        CreateTable(
            "dbo.LanguageChoices",
            c => new
                {
                    Id = c.Guid(nullable: false, identity: true),
                    Name = c.String(nullable: false, maxLength: 50),
                })
            .PrimaryKey(t => t.Id);

        Sql(String.Format("INSERT INTO LanguageChoices VALUES ('{0}','{1}')", Guid.NewGuid(), "English"));
        Sql(String.Format("INSERT INTO LanguageChoices VALUES ('{0}','{1}')", Guid.NewGuid(), "Other"));
        Sql(String.Format("INSERT INTO LanguageChoices VALUES ('{0}','{1}')", Guid.NewGuid(), "Spanish"));

        AddColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid(nullable: true));

        Sql("UPDATE Callers Set LanguageChoice_Id = (SELECT Id FROM LanguageChoices WHERE Name = \'English\') WHERE LanguageChoice_Id IS NULL");

        AlterColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid(nullable: false));

        CreateIndex("dbo.Callers", "LanguageChoice_Id");
        AddForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices", "Id", cascadeDelete: true);
    }

    public override void Down()
    {
        DropForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices");
        DropIndex("dbo.Callers", new[] { "LanguageChoice_Id" });
        DropColumn("dbo.Callers", "LanguageChoice_Id");
        DropTable("dbo.LanguageChoices");
    }
}

1 个答案:

答案 0 :(得分:1)

生成此冲突是因为新表LanguageChoices在创建时没有元素,因此,外键找不到有效值,因为它不可为空,您可以尝试更改:

 public Guid LanguageChoice_Id { get; set; }

到此:

  public Guid? LanguageChoice_Id { get; set; }

然后再次生成迁移,您可以看到以下行:

 AddColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid(nullable: false));

更改为:

 AddColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid());

现在,您可以更新数据库,并将列更改为非null,添加有效值并再次更改该行,然后生成新的迁移:

public Guid? LanguageChoice_Id { get; set; }

为:

public Guid LanguageChoice_Id { get; set; }
评论后

在标记处插入sql代码:

public partial class AddCallerLanguageChoice : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.LanguageChoices",
            c => new
                {
                    Id = c.Guid(nullable: false, identity: true),
                    Name = c.String(nullable: false, maxLength: 50),
                })
            .PrimaryKey(t => t.Id);

        string TempKey = Guid.NewGuid ( ).ToString();
        this.Sql ( String.Format ( "Insert into dbo.LanguageChoices values ({0},{1})", TempKey, "Initial" ) );

        AddColumn("dbo.Callers", "LanguageChoice_Id", c => c.Guid(nullable: false));

        Sql ( String.Format ( "Update dbo.Callers set LanguageChoice_Id='{0}' where LanguageChoice_Id is null", TempKey ) );

        CreateIndex("dbo.Callers", "LanguageChoice_Id");
        AddForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices", "Id", cascadeDelete: true);
    }

    public override void Down()
    {
        DropForeignKey("dbo.Callers", "LanguageChoice_Id", "dbo.LanguageChoices");
        DropIndex("dbo.Callers", new[] { "LanguageChoice_Id" });
        DropColumn("dbo.Callers", "LanguageChoice_Id");
        DropTable("dbo.LanguageChoices");
    }
}