在EF Core中添加一对一关系时迁移数据?
在我的一个表中添加新的一对一关系后,我无法弄清楚如何为我的数据库中的现有行添加默认数据。
升级前我的数据库基本上看起来像这样:
-- Team -- Name: TEXT -- History -- Id: INT
…其中历史是从其他不相关的表指向它的外键。
在我的升级中,我基本上希望团队有一个历史记录,所以我的新数据库看起来像:
-- Team -- Name: TEXT HistoryId: INT -- History -- Id: INT
我现在的问题是,我的数据库中有现有的团队,他们需要指向唯一的历史记录行,因此我需要为每个现有的团队创建一个新的历史记录行。
我尝试在迁移中手动添加Up方法中的条目,但由于我的模型与现有模式不匹配,因此失败。
protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( 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); }
不幸的是,目前EF Core不支持从迁移中播种数据。 该问题在其存储库中被跟踪为#629 – 种子数据 。
我目前看到的唯一解决方案是通过MigrationBuilder.Sql
方法使用旧的好SQL。 遗憾的是,无法访问db提供程序服务,因此下一步适用于SQL Server(尽管我尝试仅使用标准SQL命令)。
让原始模型如下:
public class Team { public int Id { get; set; } public string Name { get; set; } } public class History { public int Id { get; set; } }
将FK从Team
添加到History
它变为:
public class Team { public int Id { get; set; } public string Name { get; set; } public int HistoryId { get; set; } public History History { get; set; } }
自动生成的迁移是:
protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( 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); }
现在,在CreateIndex
命令之前,我们手动插入以下内容:
migrationBuilder.AddColumn( 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");
这个想法很简单。 我们在History
表中创建一个临时可为空的列TeamId
,为Team
表中的每条记录插入一条带有相应TeamId
的新记录,然后使用History
表中的TeamId
列作为键更新Team
表中的HistoryId
列,最后删除临时专栏。
此时,数据转换已完成,可以创建FK约束。
远非良好做法,但可以用作解决方法。
编辑:在Gert Arnold的评论之后 ,看起来使用SQL块是正确的方法。 我唯一关心的是如何编写数据库不可知和/或特定的SQL。 当然,如果针对单个特定数据库类型,则问题不存在。 无论如何,如果需要处理不同的数据库类型,可以始终使用所有目标数据库支持的标准SQL命令,以及基于MigrationBuilder.ActiveProvider
属性的特定if
块。
- ASP .NET CORE无法使用自定义程序集查找文件或程序集
- 在实体Framework Core中执行存储过程而不期望映射到dbset
- 执行等待异步操作时的AWS Lambda行为?
- 通过通用接口/抽象类实现使.NET Core DI自动解析类
- 将ArrayPool对象提供给JsonOutputFormatter构造函数
- 为什么Scoped服务解析为同一请求的两个不同实例?
- 调用AddUserAsync .NET Core 2.0时出现PlatformNotSupportedexception
- 将Azure ServiceBus上的消息从.NET Core发送器发送到.NET 4.6处理程序
- 使用Novell.Directory.Ldap.NETStandard库进行C#netcore ldap身份validation