EFCore 从入门到精通-5(谈谈迁移)
1.初始准备开发软件:VisualStudio2022,EFCore6.0.net Core版本:.Net6.0数据库:mysql8.0数据库管理软件:Navicat2.迁移的基本方法在实际的项目,除此设计好ER关系模型后,我们基本上可以确定数据库的框架。但是随着项目的推进,我们往往需要修改实体关系,或者新增字段,或者删除某个字段,亦或者增加新的表等。在EFCore中,我们可以采用......
1.初始准备
开发软件:VisualStudio2022,EFCore6.0
.net Core版本:.Net6.0
数据库:mysql8.0
数据库管理软件:Navicat
2.数据库的迁移
在实际的项目,除此设计好ER关系模型后,我们基本上可以确定数据库的框架。但是随着项目的推进,我们往往需要修改实体关系,或者新增字段,或者删除某个字段,亦或者增加新的表等。
在EFCore中,我们可以采用 如下方式进行迁移
Add-Migration 迁移名称//VisualStudio中使用
dotnet ef migrations add 迁移名称 //.NETCore CLI里使用
执行上述命令后,在项目文件里会生成一个叫Migrations的文件夹。
如果是第一次迁移,我们一般会在这个文件夹下,出现两个类,一个分步类,这个类主要做此次迁移的具体工作,一个是数据库快照类。
我们先看迁移类:
迁移类里主要有3个方法,其中一个分步类是Up和Down方法还有一个BuildTargetModel方法。
2.1 添加迁移
增加迁移先进行的操作主要如下:
1.编译程序,(注意:当前程序内存在编译错误,就无法迁移),
2.将新的模型与当前数据库快照进行对比,从而从而生成新迁移文件的Up和Down方法。
增加迁移后必须通过Update-DataBase 才能成功应用到数据库中。
我们来修改下项目中的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,通过Navicat打开数据库,打开Teacher表结构发现如下Teacher表多了字段Age:
除此之外我们还可以去删除或者修改某个属性,比如我们删除学生的Age属性然后进行迁移。
如上图,在修改或者删除某个属性的时候,会有警告提示,我们的操作可能导致数据库数据丢失。
2.2 迁移删除以及回退
在迁移的更改还未应用到数据库的时候可以删除迁移,但是如果已经使用Update-Database即将迁移更改应用到数据库就不能采用Remove-Migration 删除。如下图
但是我们可以采用Update-DataBase回退到前面一个应用,如下,我们使用 下面的命令回退到给Teacher 增加Age的应用这个时候数据库表Student应该是有Age属性,EFMigrationsHistory表的记录也会修改。
Update-DataBase 20220427022734_AddAge
我们再回退一次到最初的状态,添加AddRelations.
2.3 通过Sql脚本迁移
在前面我们的例子中,添加迁移后,都是通过Update-DataBase直接将迁移更改应用到数据库的,这种方法在开发阶段很方便,但是如果项目已经上线,再通过此种办法就麻烦了。
其实我们还可以通过导出Sql脚本,来进行数据库的更改。我们再给Teacher这个类,加回Aage这个属性
public class Teacher
{
public int TeacherId { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public int Age { get; set; }
}
然后执行Script-Migration,发现EFCore为我们生成了一个Sql脚本。
我们可以根据这个脚本,在某些情况下,可以根据我们实际生产使用的数据库的特定需求调整这些脚本。
因为上面的脚本是涉及到整个数据库的,除此之外,我们还可以获得局部更改的脚本,
我们可以从用下面的命令进行调整。(先前前面的更改全部应用,即添加了AddAge和RemoveStudentAge)然后执行,
Script-Migration AddRelations AddAge
我们将会得到给Teacher表添加Age属性的Sql脚本代码。
2.4 通过程序应用迁移
在程序运行时,我们也可以进行迁移的应用(通常是在启动期间),从而不用每次通过控制台,使用Update-DataBase更改应用到数据库。但是 这种方法对于迁移的本地开发和测试很有效,但不适合管理生产数据库,原因如下:
-
如果应用程序的多个实例正在运行,这两个应用程序可能会尝试同时应用迁移并失败(更糟糕的情况是导致数据损坏)。
-
同样,如果一个应用程序正在访问数据库,而另一个应用程序正在迁移它,这可能会导致严重的问题。
-
应用程序必须具有提升的访问权限才能修改数据库架构。 在生产环境中限制应用程序的数据库权限通常是一种很好的做法。
-
出现问题时,能够回滚已应用的迁移很重要。 其他策略可以轻松提供此功能,并且开箱即用。 程序会直接应用 SQL命令,不给开发人员检查或修改的机会。 这在生产环境中可能会很危险。
如果为了图方便可以在开发阶段,使用程序应用迁移,但是当程序发布的时候,将此段代码注释掉。下面举个例子来说明,我们在Student类添加一个属性Hobby,
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public int Age { get; set; }
public string Hobby { get; set; }
public StudentAddress Address { get; set; }
public IList<Course> Courses { get; set; } = new List<Course>();
}
然后添加一个迁移 Add-Migration AddHobby
修改启动代码如下:dbContext.Database.Migrate();
using (EFLearnDbContext dbContext=new EFLearnDbContext())
{
//添加自动引用迁移
dbContext.Database.Migrate();
#region 查询数据
var students = dbContext.Students.Include(x => x.Address).Include(x => x.Courses).ToList();
foreach (var st in students)
{
Console.WriteLine($"StudentId:{st.StudentId},Name:{st.Name},City:{st.Address.City}, Address:{st.Address.Address},Courses:{string.Join(",", st.Courses.Select(x => x.Name))}");
}
#endregion
}
直接运行程序,打开数据库,发现如下:
数据表多了Hobby字段。同时为了除此应用的时候代码能够自动创建数据库可以在EFLearnDbContext里添加,程序运行时保证数据库创建。
public EFCoreLearnContext()
{
Database.EnsureCreated();
}
public EFCoreLearnContext(DbContextOptions<EFCoreLearnContext> options)
: base(options)
{
Database.EnsureCreated();
}
在正式发布的程序的时候注释掉就能保证数据库的和程序的稳定性。
//dbContext.Database.Migrate();
更多推荐
所有评论(0)