mon*_*res 7 c# ef-code-first entity-framework-core .net-core
在我的一个表中添加新的一对一关系后,我无法弄清楚如何为我的数据库中的现有行添加默认数据.
升级前我的数据库基本上看起来像这样:
-- Team --
Name: TEXT
-- History --
Id: INT
Run Code Online (Sandbox Code Playgroud)
...其中History有外键从其他不相关的表中指向它.
在我的升级中,我基本上希望团队有一个历史记录,所以我的新数据库看起来像:
-- Team --
Name: TEXT
HistoryId: INT
-- History --
Id: INT
Run Code Online (Sandbox Code Playgroud)
我现在的问题是,我的数据库中有现有的团队,他们需要指向唯一的历史记录行,因此我需要为每个现有团队创建一个新的历史记录行.
我尝试在迁移中手动添加Up方法中的条目,但由于我的模型与现有模式不匹配,因此失败.
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "HistoryId",
table: "Team",
nullable: false,
defaultValue: 0);
using (var db = new XMDBContext())
{
foreach (var team in db.Team)
team.History = new XMHistory();
db.SaveChanges();
}
migrationBuilder.CreateIndex(
name: "IX_Team_HistoryId",
table: "Team",
column: "HistoryId",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Team_History_HistoryId",
table: "Team",
column: "HistoryId",
principalTable: "History",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,当前EF Core不支持从迁移中播种数据。在他们的存储库中将其跟踪为#629-种子数据。
我目前看到的唯一解决方案是使用旧的良好的SQL through MigrationBuilder.Sql方法。不幸的是,无法访问db provider服务,因此下一个适用于SQL Server(尽管我尝试仅使用标准SQL命令)。
让原始模型如下:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
}
public class History
{
public int Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Team向其添加FK之后,History它变为:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public int HistoryId { get; set; }
public History History { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
自动生成的迁移是:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "HistoryId",
table: "Team",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateIndex(
name: "IX_Team_HistoryId",
table: "Team",
column: "HistoryId");
migrationBuilder.AddForeignKey(
name: "FK_Team_History_HistoryId",
table: "Team",
column: "HistoryId",
principalTable: "History",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
Run Code Online (Sandbox Code Playgroud)
现在,在CreateIndex命令之前,我们手动插入以下内容:
migrationBuilder.AddColumn<int>(
name: "TeamId",
table: "History",
nullable: true);
migrationBuilder.Sql(@"insert into History (TeamId) select Id from Team");
migrationBuilder.Sql(@"update Team set HistoryId = (select Id from History where TeamId = Team.Id)");
migrationBuilder.DropColumn(
name: "TeamId",
table: "History");
Run Code Online (Sandbox Code Playgroud)
这个想法很简单。我们创建一个临时空列TeamId在History表中插入相应的新纪录TeamId为每个记录Team表,然后更新HistoryId列Team使用表TeamId列从History表作为重点,最后删除临时列。
至此,数据转换完成,可以创建FK约束。
远离良好实践,但可以用作解决方法。
编辑:在Gert Arnold的评论之后,看起来像使用SQL块是正确的方法。我唯一关心的是如何编写与数据库无关的SQL和/或特定的SQL。当然,如果针对一个特定的数据库类型,则该问题不存在。无论如何,如果需要处理不同的数据库类型,则可以始终使用所有目标数据库支持的标准SQL命令以及if基于MigrationBuilder.ActiveProvider属性的特定块。
| 归档时间: |
|
| 查看次数: |
884 次 |
| 最近记录: |