Entity Framework- 代码优先迁移

Entity Framework 4.3包含一个新的Code First Migrations功能,允许您随着模型的变化逐步改进数据库模式.对于大多数开发人员来说,这是对4.1和4.2版本中数据库初始化程序选项的重大改进,这些选项要求您手动更新数据库,或者在模型更改时删除并重新创建它.

  • 在Entity Framework 4.3之前,如果您的数据库中已有数据(种子数据除外)或现有的存储过程,触发器等,这些策略过去会丢弃整个数据库数据库并重新创建它,因此您将丢失数据和其他数据库对象.

  • 通过迁移,当模型更改时,它将自动更新数据库模式丢失任何现有数据或其他数据库对象.

  • 它使用名为MigrateDatabaseToLatestVersion的新数据库初始化程序.

有两种迁移和减去;

  • 自动迁移

  • 基于代码的迁移

自动迁移

Automa迁移最初是在实体框架4.3中引入的.在自动迁移中,您无需在代码文件中手动处理数据库迁移.例如,对于每个更改,您还需要更改域类.但是,通过自动迁移,您只需在Package Manager Console中运行命令即可完成此操作.

让我们看一下自动迁移的以下分步过程.

当您使用Code First方法时,您没有适合您的应用程序的数据库.

在本例中,我们将从3个基本类开始例如学生,课程和注册,如下面的代码所示.

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

Command

第3步 : 命令成功运行后,它会在项目的Migration文件夹中创建一个内部密封的Configuration类,如下面的代码所示.

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表已添加到您的数据库中.

StudentsLogIn

上述自动迁移步骤仅适用于您的实体.例如,要添加另一个实体类或删除现有的实体类,它将成功迁移.但是,如果你向实体类中添加或删除任何属性,那么它将抛出异常.

步骤10 : 要处理属性迁移,您需要在配置类构造函数中设置AutomaticMigrationDataLossAllowed = true.

public Configuration() {
   AutomaticMigrationsEnabled = true;
   AutomaticMigrationDataLossAllowed = true;
   ContextKey = "EFCodeFirstDemo.MyContext";
}

基于代码的迁移

开发新应用程序时,数据模型会频繁更改,每次模型更改时,它都会与数据库不同步.您已将实体框架配置为每次更改数据模型时自动删除并重新创建数据库.当您想要更多地控制迁移时,基于代码的迁移非常有用.

  • 添加,删除或更改实体时类或更改您的DbContext类,下次运行应用程序时,它会自动删除您现有的数据库,创建一个与模型匹配的新数据库,并将其与测试数据一起播种.

  • Code First Migrations功能通过启用Code First来更新数据库模式而不是删除和重新创建数据库来解决此问题.要部署应用程序,您必须启用迁移.

以下是迁移数据库中的更改的基本规则 :

  • 启用迁移

  • 添加迁移

  • 更新数据库

让我们看看以下逐步迁移代码库的过程.

你使用代码优先方法,你没有为你的应用程序提供数据库.

在这个例子中,我们将重新开始我们的3个基本类,如学生,课程和注册,如图所示在以下代码中.

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文件夹中看到一个新文件,其中包含您传递给命令的参数名称,并带有时间戳前缀,如下图所示.

TimeStamp Prefix

第5步 : 您可以使用"update-database"命令创建或更新数据库.

PM> Update-Database -Verbose

"-Verbose"标志指定在控制台中显示应用于目标数据库的SQL语句.

第6步 : 让我们在学生班中再添加一个属性'Age',然后执行更新语句.

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时,当命令成功执行时你会看到新列年龄已添加到您的数据库中.

新列时代

我们建议您逐步执行上述示例,以便更好地理解.