Entity Framework - Code First Migration

Entity Framework 4.3 bao gồm một tính năng Code First Migrations mới cho phép bạn từng bước phát triển lược đồ cơ sở dữ liệu khi mô hình của bạn thay đổi theo thời gian. Đối với hầu hết các nhà phát triển, đây là một cải tiến lớn so với các tùy chọn khởi tạo cơ sở dữ liệu từ các phiên bản 4.1 và 4.2 yêu cầu bạn cập nhật cơ sở dữ liệu theo cách thủ công hoặc thả và tạo lại nó khi mô hình của bạn thay đổi.

  • Trước Entity Framework 4.3, nếu bạn đã có dữ liệu (ngoài dữ liệu gốc) hoặc các thủ tục, trình kích hoạt được lưu trữ, v.v. trong cơ sở dữ liệu của mình, thì các chiến lược này được sử dụng để loại bỏ toàn bộ cơ sở dữ liệu và tạo lại nó, vì vậy bạn sẽ mất dữ liệu và các DB khác các đối tượng.

  • Với việc di chuyển, nó sẽ tự động cập nhật giản đồ cơ sở dữ liệu, khi mô hình của bạn thay đổi mà không làm mất bất kỳ dữ liệu hiện có nào hoặc các đối tượng cơ sở dữ liệu khác.

  • Nó sử dụng một trình khởi tạo cơ sở dữ liệu mới có tên MigrateDatabaseToLatestVersion.

Có hai loại Di cư -

  • Di chuyển tự động
  • Di chuyển dựa trên mã

Di chuyển tự động

Di chuyển tự động lần đầu tiên được giới thiệu trong Entity framework 4.3. Trong quá trình di chuyển tự động, bạn không cần phải xử lý quá trình di chuyển cơ sở dữ liệu theo cách thủ công trong tệp mã. Ví dụ: đối với mỗi thay đổi, bạn cũng sẽ cần thay đổi trong các lớp miền của mình. Nhưng với di chuyển tự động, bạn chỉ cần chạy một lệnh trong Bảng điều khiển Trình quản lý Gói để thực hiện việc này.

Hãy cùng xem quy trình di chuyển tự động từng bước sau đây.

Khi bạn sử dụng cách tiếp cận Code First, bạn không có cơ sở dữ liệu cho ứng dụng của mình.

Trong ví dụ này, chúng ta sẽ bắt đầu với 3 lớp cơ bản của chúng ta như Sinh viên, Khóa học và Ghi danh như được hiển thị trong đoạn mã sau.

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; }

}

Sau đây là lớp ngữ cảnh.

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; }
}

Trước khi chạy ứng dụng, bạn cần bật tính năng di chuyển tự động.

Step 1 - Mở Bảng điều khiển Trình quản lý gói từ Công cụ → Trình quản lý gói NuGet → Bảng điều khiển Trình quản lý gói.

Step 2 - Để kích hoạt di chuyển tự động, hãy chạy lệnh sau trong Bảng điều khiển Trình quản lý Gói.

PM> enable-migrations -EnableAutomaticMigrations:$true

Step 3 - Khi lệnh chạy thành công, nó sẽ tạo một lớp Cấu hình được niêm phong nội bộ trong thư mục Di chuyển của dự án của bạn như được hiển thị trong đoạn mã sau.

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" }
         //  );
      }
   }
}

Step 4 - Đặt trình khởi tạo cơ sở dữ liệu trong lớp ngữ cảnh với chiến lược khởi tạo DB mới 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; }

}

Step 5- Bạn đã thiết lập di chuyển tự động. Khi bạn thực thi ứng dụng của mình, ứng dụng sẽ tự động thực hiện quá trình di chuyển khi bạn thay đổi mô hình.

Step 6- Như bạn có thể thấy rằng một bảng hệ thống __MigrationHistory cũng được tạo trong cơ sở dữ liệu của bạn với các bảng khác. Trong __MigrationHistory, di chuyển tự động duy trì lịch sử thay đổi cơ sở dữ liệu.

Step 7- Khi bạn thêm một lớp thực thể khác làm lớp miền và thực thi ứng dụng của bạn, thì nó sẽ tạo bảng trong cơ sở dữ liệu của bạn. Hãy thêm lớp StudentLogIn sau.

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; }
}

Step 8 - Đừng quên thêm DBSet cho lớp được đề cập ở trên trong lớp ngữ cảnh của bạn như được hiển thị trong đoạn mã sau.

public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }

Step 9 - Chạy lại ứng dụng của bạn và bạn sẽ thấy rằng bảng StudentsLogIn được thêm vào cơ sở dữ liệu của bạn.

Các bước được đề cập ở trên để di chuyển tự động sẽ chỉ hoạt động đối với thực thể của bạn. Ví dụ: để thêm một lớp thực thể khác hoặc xóa lớp thực thể hiện có, nó sẽ di chuyển thành công. Nhưng nếu bạn thêm hoặc xóa bất kỳ thuộc tính nào vào lớp thực thể của mình thì nó sẽ ném ra một ngoại lệ.

Step 10 - Để xử lý việc di chuyển thuộc tính, bạn cần đặt AutomaticMigrationDataLossAllowed = true trong phương thức khởi tạo lớp cấu hình.

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

Di chuyển dựa trên mã

Khi bạn phát triển một ứng dụng mới, mô hình dữ liệu của bạn thay đổi thường xuyên và mỗi khi mô hình thay đổi, nó sẽ không đồng bộ với cơ sở dữ liệu. Bạn đã định cấu hình Khung thực thể để tự động thả và tạo lại cơ sở dữ liệu mỗi khi bạn thay đổi mô hình dữ liệu. Di chuyển dựa trên mã rất hữu ích khi bạn muốn kiểm soát nhiều hơn việc di chuyển.

  • Khi bạn thêm, xóa hoặc thay đổi các lớp thực thể hoặc thay đổi lớp DbContext của mình, lần sau khi bạn chạy ứng dụng, nó sẽ tự động xóa cơ sở dữ liệu hiện có của bạn, tạo một cơ sở dữ liệu mới phù hợp với mô hình và gieo nó bằng dữ liệu thử nghiệm.

  • Tính năng Code First Migrations giải quyết vấn đề này bằng cách cho phép Code First cập nhật giản đồ cơ sở dữ liệu thay vì xóa và tạo lại cơ sở dữ liệu. Để triển khai ứng dụng, bạn sẽ phải bật Migrations.

Đây là quy tắc cơ bản để di chuyển các thay đổi trong cơ sở dữ liệu -

  • Bật di chuyển
  • Thêm di chuyển
  • Cập nhật cơ sở dữ liệu

Hãy xem quy trình từng bước của quá trình di chuyển cơ sở mã sau đây.

Khi bạn sử dụng cách tiếp cận mã đầu tiên, bạn không có cơ sở dữ liệu cho ứng dụng của mình.

Trong ví dụ này, chúng tôi sẽ bắt đầu lại với 3 lớp cơ bản của chúng tôi như Sinh viên, Khóa học và Ghi danh như được hiển thị trong đoạn mã sau.

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; }

}

Sau đây là lớp ngữ cảnh.

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; }

}

Step 1 - Trước khi chạy ứng dụng, bạn cần kích hoạt tính năng di chuyển.

Step 2 - Mở Bảng điều khiển Trình quản lý Gói từ Công cụ → Trình quản lý gói NuGet → Bảng điều khiển Trình quản lý gói.

Step 3 - Di chuyển đã được bật, bây giờ hãy thêm di chuyển trong ứng dụng của bạn bằng cách thực hiện lệnh sau.

PM> add-migration "UniDB Schema"

Step 4 - Khi lệnh được thực hiện thành công, bạn sẽ thấy một tệp mới đã được tạo trong thư mục Migration với tên của tham số bạn đã truyền vào lệnh với tiền tố dấu thời gian như trong hình sau.

Step 5 - Bạn có thể tạo hoặc cập nhật cơ sở dữ liệu bằng lệnh “update-database”.

PM> Update-Database -Verbose

Cờ "-Verbose" chỉ định hiển thị các Câu lệnh SQL đang được áp dụng cho cơ sở dữ liệu đích trong bảng điều khiển.

Step 6 - Hãy thêm một thuộc tính nữa 'Tuổi' trong lớp sinh viên và sau đó thực hiện câu lệnh cập nhật.

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; }

}

Khi bạn thực thi PM → Update-Database –Verbose, khi lệnh được thực thi thành công, bạn sẽ thấy cột Age mới được thêm vào cơ sở dữ liệu của bạn.

Chúng tôi khuyên bạn nên thực hiện ví dụ trên theo cách từng bước để hiểu rõ hơn.