实体框架 – 代码优先迁移
实体框架 – 代码优先迁移
Entity Framework 4.3 包含一个新的 Code First 迁移功能,该功能允许您随着模型的变化而逐步改进数据库架构。对于大多数开发人员来说,这比 4.1 和 4.2 版本中的数据库初始化程序选项有了很大的改进,这些选项要求您在模型更改时手动更新数据库或删除并重新创建它。
-
在 Entity Framework 4.3 之前,如果您的数据库中已经有数据(种子数据除外)或现有的存储过程、触发器等,这些策略用于删除整个数据库并重新创建它,因此您将丢失数据和其他数据库对象。
-
通过迁移,它会在您的模型更改时自动更新数据库架构,而不会丢失任何现有数据或其他数据库对象。
-
它使用名为 MigrateDatabaseToLatestVersion 的新数据库初始值设定项。
有两种迁移 –
- 自动迁移
- 基于代码的迁移
自动迁移
自动迁移首先在实体框架 4.3 中引入。在自动迁移中,您不需要在代码文件中手动处理数据库迁移。例如,对于每次更改,您还需要更改域类。但是通过自动迁移,您只需在包管理器控制台中运行命令即可完成此操作。
下面我们来看看自动化迁移的分步过程。
当您使用 Code First 方法时,您的应用程序没有数据库。
在此示例中,我们将从 3 个基本类开始,例如 Student、Course 和 Enrollment,如下面的代码所示。
public class Enrollment { public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public Grade? Grade { get; set; } public virtual Course Course { get; set; } public virtual Student Student { get; set; } } public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } public class Course { public int CourseID { get; set; } public string Title { get; set; } [Index] public int Credits { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }
以下是上下文类。
public class MyContext : DbContext { public MyContext() : base("MyContextDB") {} public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
在运行应用程序之前,您需要启用自动迁移。
步骤 1 – 从工具 → NuGet 包管理器 → 包管理器控制台打开包管理器控制台。
步骤 2 – 要启用自动迁移,请在包管理器控制台中运行以下命令。
PM> enable-migrations -EnableAutomaticMigrations:$true
步骤 3 – 命令成功运行后,它会在项目的迁移文件夹中创建一个内部密封的配置类,如下面的代码所示。
namespace EFCodeFirstDemo.Migrations { using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstDemo.MyContext> { public Configuration() { AutomaticMigrationsEnabled = true; ContextKey = "EFCodeFirstDemo.MyContext"; } protected override void Seed(EFCodeFirstDemo.MyContext context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. E.g. // context.People.AddOrUpdate( // p ⇒ p.FullName, // new Person { FullName = "Andrew Peters" }, // new Person { FullName = "Brice Lambson" }, // new Person { FullName = "Rowan Miller" } // ); } } }
第 4 步– 使用新的数据库初始化策略 MigrateDatabaseToLatestVersion 在上下文类中设置数据库初始值设定项。
public class MyContext : DbContext { public MyContext() : base("MyContextDB") { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB")); } public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
第 5 步– 您已设置自动迁移。当您执行应用程序时,当您更改模型时,它会自动处理迁移。
第 6 步– 如您所见,在您的数据库中还与其他表一起创建了一个系统表 __MigrationHistory。在__MigrationHistory 中,自动迁移维护数据库更改的历史记录。
第 7 步– 当您添加另一个实体类作为域类并执行您的应用程序时,它将在您的数据库中创建表。让我们添加以下 StudentLogIn 类。
public class StudentLogIn { [Key, ForeignKey("Student")] public int ID { get; set; } public string EmailID { get; set; } public string Password { get; set; } public virtual Student Student { get; set; } }
步骤 8 – 不要忘记在上下文类中为上述类添加 DBSet,如下面的代码所示。
public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }
第 9 步– 再次运行您的应用程序,您将看到 StudentsLogIn 表已添加到您的数据库中。
上述针对自动迁移的步骤仅适用于您的实体。例如,要添加另一个实体类或删除现有实体类,它将成功迁移。但是,如果您向实体类添加或删除任何属性,则会引发异常。
第 10 步– 要处理属性迁移,您需要在配置类构造函数中设置 AutomaticMigrationDataLossAllowed = true。
public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; ContextKey = "EFCodeFirstDemo.MyContext"; }
基于代码的迁移
当您开发一个新应用程序时,您的数据模型会频繁更改,并且每次模型更改时,它都会与数据库不同步。您已将实体框架配置为每次更改数据模型时自动删除并重新创建数据库。当您希望对迁移进行更多控制时,基于代码的迁移非常有用。
-
当您添加、删除或更改实体类或更改 DbContext 类时,下次运行应用程序时,它会自动删除您现有的数据库,创建一个与模型匹配的新数据库,并用测试数据为其播种。
-
Code First 迁移功能通过启用 Code First 来更新数据库架构而不是删除和重新创建数据库来解决此问题。要部署应用程序,您必须启用迁移。
这是迁移数据库更改的基本规则 –
- 启用迁移
- 添加迁移
- 更新数据库
下面我们来看看代码库迁移的分步过程。
当您使用代码优先方法时,您的应用程序没有数据库。
在此示例中,我们将重新开始使用我们的 3 个基本类,例如 Student、Course 和 Enrollment,如下面的代码所示。
public class Enrollment { public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public Grade? Grade { get; set; } public virtual Course Course { get; set; } public virtual Student Student { get; set; } } public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } public class Course { public int CourseID { get; set; } public string Title { get; set; } [Index] public int Credits { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }
以下是上下文类。
public class MyContext : DbContext { public MyContext() : base("MyContextDB") { Database.SetInitializer(new MigrateDatabaseToLatestVersion< MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB")); } public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
步骤 1 – 在运行应用程序之前,您需要启用迁移。
步骤 2 – 从工具 → NuGet 包管理器 → 包管理器控制台打开包管理器控制台。
第 3 步– 迁移已启用,现在通过执行以下命令在您的应用程序中添加迁移。
PM> add-migration "UniDB Schema"
步骤 4 – 成功执行命令后,您将看到在 Migration 文件夹中创建了一个新文件,其中包含您传递给命令的参数名称,并带有时间戳前缀,如下图所示。
第 5 步– 您可以使用“update-database”命令创建或更新数据库。
PM> Update-Database -Verbose
“-Verbose”标志指定在控制台中显示应用于目标数据库的 SQL 语句。
第 6 步– 让我们在学生类中再添加一个属性“年龄”,然后执行更新语句。
public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public int Age { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }
当你执行 PM → Update-Database –Verbose 时,当命令成功执行时你会看到你的数据库中添加了新的列 Age。
我们建议您逐步执行上述示例,以便更好地理解。