C# 如何将新表中的新外键添加到现有记录中
使用C#MVC和实体框架v6.2.0 我有一个现有型号,C# 如何将新表中的新外键添加到现有记录中,c#,entity-framework,tsql,C#,Entity Framework,Tsql,使用C#MVC和实体框架v6.2.0 我有一个现有型号,Caller public class Caller { [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } [Required] public string FirstName { get; set; } } public class Caller { [Key, Data
Caller
public class Caller
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string FirstName { get; set; }
}
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; } // <----
}
我创建了一个新模型,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 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; } // <----
}
当我添加语言选项
时,预期结果如下:
╔═════════════════════╦═══════════╦═════════════════════════════╗
║ 身份证件║ 名字║ 语言选择║
╠═════════════════════╬═══════════╬═════════════════════════════╣
║ 调用方\u guid\u值\u 1║ 赖安║ 语言选择\u guid\u值\u 1║
║ 调用方\u guid\u值\u 2║ 约翰║ 语言选择\u guid\u值\u 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语句与外键约束“FK_dbo.Callers_dbo.LanguageChoices_LanguageChoice_Id”冲突。冲突发生在数据库“aspnet My Web App-20171030040324”表“dbo.LanguageChoices”列“Id”中
有没有办法做到这一点,或者我应该继续允许LanguageChoice\u Id
为空?
4年前的类似问题:
- 4岁的时候,也许从那以后有些事情发生了变化
- 他们使用的是Id的
值,我使用的是int
,所以我不能提前猜测/假设Id值Guid
- 我希望避免创建一个迁移,其中
可为空,然后是更新记录的种子方法,然后是另一个迁移,使LanguageChoice\u Id
不可为空,因为将这两个迁移推到Azure时会中断,因为种子方法将最后运行。(见Ari Roth对RicklsWright回答的评论)LanguageChoice\u Id
更新: 在“更新的答案”之后,我找到了一个有效的迁移文件 Henoc的答案是公认的答案,这只是为了说明我最终得到了什么,不同之处在于我在这里插入了表值,并使用非临时值更新了
调用者的空值:
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在创建时没有元素,因此,外键找不到有效值,因为它不可为null,您可以尝试更改:
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());
现在,您可以更新数据库,并将列更改为NOTNULL,添加有效值并再次更改行,然后生成新迁移:
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");
}
}
到目前为止,一切都没有改变(很不幸)。@IvanStoev好吧,这是一个令人沮丧的问题。这与我在帖子底部提到的问题不谋而合。我打算将这两个迁移同时推送到另一台服务器(我也会这样做)在EF尝试将空值更新为不可为空的字段之前,我将无法更改空值,因此会出现错误。您是否尝试在迁移和新表中创建列后插入sql代码以将值分配给新列?您可以在仅包含update语句的架构更改迁移之间的中间迁移:Sql(“update…”)
根据您的建议,@BradleyUffner,我在它自己的迁移中有这样一句话:string sqlStatement=“UPDATE Callers SET LanguageChoice\u Id=\'”+LanguageChoice.Id+“\'WHERE LanguageChoice\u Id为NULL”;Sql(sqlStatement)代码>之后的迁移使LanguageChoice\u Id
不可为空,这在一次执行一个迁移时有效,但不能同时执行所有迁移。我必须使用<代码> AptudioDbValue获得<代码> ID>代码>值,所以在迁移过程中,它错误地说AppultDbCurror已经更改。我编辑了我的ANSIS,请在评论之后再查看。