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();

EFCore 从入门到精通-4(映射关系与导航属性)
EFCore 从入门到精通-6(详谈查询)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐