c# - 如何将新表中的新外键添加到现有记录

标签 c# entity-framework t-sql

使用 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; }
}

我想添加这个新的LanguageChoiceCaller

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; } // <----
}

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

在我的数据库中,我已有 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");
    }
}

这给我带来了错误:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Callers_dbo.LanguageChoices_LanguageChoice_Id". The conflict occurred in database "aspnet-My Web App-20171030040324", table "dbo.LanguageChoices", column 'Id'.

有没有办法做到这一点,或者我应该继续允许 LanguageChoice_Id可以为空吗?


4年前的类似问题:Entity Framework The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

  • 4岁了,也许从那时起有些事情发生了变化
  • 他们正在使用int Id 值,我正在使用 Guid ,所以我无法提前猜测/假设 Id 值
  • 我想避免创建一个迁移,其中 LanguageChoice_Id可以为空,然后是更新记录的种子方法,然后是另一个迁移,使 LanguageChoice_Id不可为空,因为将两个迁移推送到 Azure 时会中断,因为种子方法将最后运行。 (请参阅 Ari Roth 对 RicklsWright 的回答的评论)


更新:

已关注 @henoc salinas '更新的答案我来到了这个有效的单一迁移文件。

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");
    }
}

最佳答案

产生此冲突的原因是新表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());

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

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");
    }
}

关于c# - 如何将新表中的新外键添加到现有记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49241816/

相关文章:

sql - |DataDirectory| 在哪里定义?

c# - 实现死锁异常的重试逻辑

sql - PIVOT 并插入每 N 行

c# - 我的依赖属性仅以一种方式绑定(bind)

c# - 为什么 SWITCH...CASE 不采用 'char' ?

c# - 什么是 EF 默认 ID 命名约定代码优先?

SQL:连接两个表,其中一个表具有不同的行

sql - SQL查询不同列的数据控制

c# - 如何在 Windows 中强制显示检测?

c# - 在控制台应用程序中使用数据注释(特别是数据类型)