EFCore:谈谈数据迁移、回退等方面
在实际的项目,ER关系模型确定后,基本上可以确定数据库的框架。随着项目的推进或者需求的变化,往往需要修改实体关系(例如:新增字段,删除字段,增加新表等)。
在EFCore中,我们可以采用如下方式进行迁移:
Add-Migration 迁移名称//VisualStudio中使用 dotnet ef migrations add 迁移名称 //.NETCore CLI里使用
执行上述命令后,在项目文件里会生成一个叫Migrations的文件夹。
如果是第一次迁移,我们一般会在这个文件夹下,出现两个类,一个分步类,这个类主要做此次迁移的具体工作,一个是数据库快照类。
迁移类里主要有3个方法,其中一个分步类是Up和Down方法还有一个BuildTargetModel方法。
1、添加迁移
1.1增加迁移先进行的操作主要如下:
<1>编译程序,(注意:当前程序内存在编译错误,就无法迁移),
<2>将新的模型与当前数据库快照进行对比,从而从而生成新迁移文件的Up和Down方法。
<3>增加迁移后必须通过Update-DataBase 才能成功应用到数据库中。
1.2示例
修改下Teacher 实体类,增加一个字段为Age,代码如下:
public class Teacher { public int TeacherId { get; set; } public string Name { get; set; } public string Title { get; set; } public int Age { get; set; } //一对多 public IList<Course> Courses { get; set; } = new List<Course>(); }
添加一个Add-Migration AddTeacherAge,然后Update-Database;
在修改或者删除某个属性的时候,会有警告提示,我们的操作可能导致数据库数据丢失。
迁移删除以及回退
在迁移的更改还未应用到数据库的时候可以删除迁移,但是如果已经使用Update-Database即将迁移更改应用到数据库就不能采用Remove-Migration 删除。但是我们可以采用Update-DataBase回退到前面一个应用,如下,我们使用 下面的命令回退到给Teacher 增加Age的应用这个时候数据库表Student应该是有Age属性,EFMigrationsHistory表的记录也会修改。
Update-DataBase 20231225143649_AddTeacherAge
2、通过Sql脚本迁移
已经上线的项目,再通过Update-DataBase就会很麻烦。我们可以通过导出Sql脚本,来进行数据库的更改。我们再给Teacher这个类,加回Age这个属性。
2.1修改下Teacher 实体类,增加一个字段为Age,代码如下:
public class Teacher { public int TeacherId { get; set; } public string Name { get; set; } public string Title { get; set; } public int Age { get; set; } //一对多 public IList<Course> Courses { get; set; } = new List<Course>(); }
2.2执行Script-Migration,获得代码如下:
CREATE TABLE IF NOT EXISTS `__EFMigrationsHistory` ( `MigrationId` varchar(150) CHARACTER SET utf8mb4 NOT NULL, `ProductVersion` varchar(32) CHARACTER SET utf8mb4 NOT NULL, CONSTRAINT `PK___EFMigrationsHistory` PRIMARY KEY (`MigrationId`) ) CHARACTER SET utf8mb4; START TRANSACTION; ALTER DATABASE CHARACTER SET utf8mb4; CREATE TABLE `Students` ( `StudentId` int NOT NULL AUTO_INCREMENT, `Name` varchar(50) CHARACTER SET utf8mb4 NOT NULL, `Sex` varchar(5) CHARACTER SET utf8mb4 NOT NULL, `Age` int NOT NULL, CONSTRAINT `PK_Students` PRIMARY KEY (`StudentId`) ) CHARACTER SET utf8mb4; CREATE TABLE `Teachers` ( `TeacherId` int NOT NULL AUTO_INCREMENT, `Name` varchar(50) CHARACTER SET utf8mb4 NULL, `Title` varchar(50) CHARACTER SET utf8mb4 NULL, CONSTRAINT `PK_Teachers` PRIMARY KEY (`TeacherId`) ) CHARACTER SET utf8mb4; CREATE TABLE `Addresses` ( `StudentAddressId` int NOT NULL AUTO_INCREMENT, `Address` varchar(500) CHARACTER SET utf8mb4 NOT NULL, `City` varchar(100) CHARACTER SET utf8mb4 NOT NULL, `StudentId` int NOT NULL, CONSTRAINT `PK_Addresses` PRIMARY KEY (`StudentAddressId`), CONSTRAINT `FK_Addresses_Students_StudentId` FOREIGN KEY (`StudentId`) REFERENCES `Students` (`StudentId`) ON DELETE CASCADE ) CHARACTER SET utf8mb4; CREATE TABLE `Courses` ( `CourseId` int NOT NULL AUTO_INCREMENT, `Name` varchar(50) CHARACTER SET utf8mb4 NULL, `TeacherId` int NULL, CONSTRAINT `PK_Courses` PRIMARY KEY (`CourseId`), CONSTRAINT `FK_Courses_Teachers_TeacherId` FOREIGN KEY (`TeacherId`) REFERENCES `Teachers` (`TeacherId`) ON DELETE RESTRICT ) CHARACTER SET utf8mb4; CREATE TABLE `CourseStudent` ( `CoursesCourseId` int NOT NULL, `StudentsStudentId` int NOT NULL, CONSTRAINT `PK_CourseStudent` PRIMARY KEY (`CoursesCourseId`, `StudentsStudentId`), CONSTRAINT `FK_CourseStudent_Courses_CoursesCourseId` FOREIGN KEY (`CoursesCourseId`) REFERENCES `Courses` (`CourseId`) ON DELETE CASCADE, CONSTRAINT `FK_CourseStudent_Students_StudentsStudentId` FOREIGN KEY (`StudentsStudentId`) REFERENCES `Students` (`StudentId`) ON DELETE CASCADE ) CHARACTER SET utf8mb4; CREATE UNIQUE INDEX `IX_Addresses_StudentId` ON `Addresses` (`StudentId`); CREATE INDEX `IX_Courses_TeacherId` ON `Courses` (`TeacherId`); CREATE INDEX `IX_CourseStudent_StudentsStudentId` ON `CourseStudent` (`StudentsStudentId`); INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) VALUES ('20231225134819_Initial', '5.0.17'); COMMIT; START TRANSACTION; ALTER TABLE `Teachers` ADD `Age` int NOT NULL DEFAULT 0; INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) VALUES ('20231225143649_AddTeacherAge', '5.0.17'); COMMIT;
上面是全部的SQL代码,我们可以摘取自己想要的代码区实现具体数据库的修改。