Code First Migration trong Entity Framework

Trong bài viết này, mình sẽ không nhằm giới thiệu về Code First trong Entity Framework nói chung, mà sẽ tập trung giới thiệu cho các bạn biết về Code First Migration và những vấn đề liên quan đến nó. Nếu bạn chưa biết Code First là gì, bạn có thể đọc sơ qua về bài viết trước đó của mình tại đây: Giới thiệu về Code First.

1. Code First Migration là gì?

Đơn giản, Code First Migration đề cập đến vấn đề bạn gặp phải khi cập nhật CSDL như thêm cột, xóa cột, tạo bảng mới và cập nhật vào CSDL đang có khi bạn sử dụng Code First trong Entity Framework. Việc cập nhật sẽ được thực hiện tự động mỗi khi có thay đổi trong các model mà bạn đã khai báo.

Ví dụ mẫu sử dụng trong bài viết

Trong bài này, giả sử mình có 2 lớp chính (2 bảng dữ liệu sau này) như sau:


public class Blog
 {
 public int BlogId { get; set; }
 public string Name { get; set; }

 public virtual List<Post> Posts { get; set; }
 }
public class Post
 {
 public int PostId { get; set; }
 public string Title { get; set; }
 public string Content { get; set; }

 public int BlogId { get; set; }
 public virtual Blog Blog { get; set; }
 }

Cấu trúc solution mẫu sử dụng trong bài viết này như sau:

codefirst_migrations_1

Trong đó, mình cài đặt Entity Framework cho 2 project là DataLayer vàConsoleApplication bằng cách sử dụng Nuget Package Manager Console với lệnh Install-Package EntityFramework. Tập tin BloggingContext.cs có nội dung như sau:

</pre>
public class BloggingContext : DbContext
 {
 public DbSet<Blog> Blogs { get; set; }
 public DbSet<Post> Posts { get; set; }
 }
<pre>

Tạo CSDL mới

Trong tập tin Program.cs trong ConsoleApplication project, bạn điền vào mã nguồn như sau:


static void Main(string[] args)
 {
 CreateDabase();
 }

 public static void CreateDabase()
 {
 var context = new BloggingContext();
 context.Database.Initialize(true);
 }

Bạn build solution và mở SQL Management Studio lên để xem CSDL mới đã được tạo ra hay chưa.

codefirst_migrations_2

Về mặc định, EF đã có migration trong đó là tạo CSDL mới nếu chưa có. Vậy, nếu model thay đổi thì thế nào? Chúng ta sẽ thay đổi mã nguồn 1 chút để xem xét tình huống này.


public class Post
 {
 public int PostId { get; set; }
 [Required]
 public string Title { get; set; }
 [Required]
 public string Content { get; set; }
 public string Note { get; set; }

 public int BlogId { get; set; }
 public virtual Blog Blog { get; set; }
 }

Chúng ta mong muốn là tạo thêm 1 trường Note nữa trong bảng Posts và sau khi build solution thì CSDL sẽ cập nhật bảng này cho chúng ta, nhưng..

codefirst_migrations_3

Lỗi xảy ra, vì như đã nói ở trên, EF đặt migration mặc định là tạo mới CSDL nếu nó chưa tồn tại, nhưng trong trường hợp này thì nó đã tồn tại rồi. EF tìm trong Post class những thuộc tính sẽ đưa vào thành trường của bảng và xem xem lớp này có gì thay đổi không. Công việc bây giờ, chúng ta sẽ thực hiện việc migration với công việc đầu tiên là “mở” migration cho DataLayer project bằng cách gõ lệnh sau trong Nuget Package Manager Console


Enable-Migrations

codefirst_migrations_4

Trong DataLayer project xuất hiện thêm thư mục và class mới.

codefirst_migrations_5

Tập tin .._InitialCreate.cs vừa mới tạo ra nhằm mục đích cấu hình việc tạo bảng mới với các trường lấy từ các thuộc tính khai báo trong các class trong DomainClasses.

2. Tự động hóa migration

Để thực hiện việc này, trong tập tin Configuration.cs, chúng ta sẽ thay đổi giá trị của AutomaticMigrationsEnabled thành true.


public Configuration()
 {
 AutomaticMigrationsEnabled = true;
 }

3. Thiết lập việc hình thành CSDL với migration

Trong tập tin Program.cs của ConsoleApplication project, thêm vào dòng mã nguồn sau:


static void Main(string[] args)
 {
 Database.SetInitializer(new MigrateDatabaseToLatestVersion<BloggingContext, Configuration>());
 CreateDabase();
 }

Bạn sẽ nhận thấy ở đây, Configuration không được nhận ra, lý do là vì Configuration class được đặt là internal sealed.

codefirst_migrations_6

Đơn giản, để giải quyết vấn đề này, ta chỉ cần chỉnh lại thành public class. Sau đó, chúng ta build lại solution và xem kết quả.

codefirst_migrations_7

4. Migration với CSDL đã có sẵn dữ liệu

Chúng ta sẽ thêm 1 thuộc tính mới là NewNote vào Post class và build lại solution và xem kết quả.

codefirst_migrations_8

Bạn có thể thấy rằng dữ liệu trước đó vẫn còn giữ và trường mới được thêm vào đã được cập nhật trong bảng. Điều đó cho thấy rằng, EF tự động theo dõi các model để xem chúng có thay đổi hay không, nếu có, nếu bạn thiết lập chế độ migration tự động thì EF sẽ điều chỉnh model theo mà không cần thêm bất kì migration nào khác. Nhưng đó mới chỉ là việc chúng ta thêm thuộc tính vào, vậy trường hợp chúng ta bỏ thuộc tính ra thì sao, hãy thử bỏ 2 thuộc tính Note và NewNote ra, build lại solution và xem kết quả thế nào.

codefirst_migrations_9

Lỗi xảy ra với cảnh báo là việc migration không được thực hiện vì trường xóa đó có dữ liệu và mặc định EF không thực hiện việc xóa trường khi có dữ liệu để đảm bảo toàn vẹn dữ liệu. Để cho phép việc xóa trường có dữ liệu, bạn thêm vào thiết lập sau:


public Configuration()
 {
 AutomaticMigrationsEnabled = true;
 AutomaticMigrationDataLossAllowed = true;
 }

Sau đó, bạn build lại solution và xem kết quả

codefirst_migrations_10

Đó là những trường hợp thay đổi trên model đã có, vậy với model mới được tạo ra sẽ như thế nào? Nó có được tạo bảng và cập nhật vào CSDL hay không? Chúng ta hãy thêm vào 1 class mới với các thông tin như sau:


public class User
 {
 public int UserId { get; set; }
 public DateTime SignInDate { get; set; }
 }
public class BloggingContext : DbContext
 {
 public DbSet<Blog> Blogs { get; set; }
 public DbSet<Post> Posts { get; set; }
 public DbSet<User> Users { get; set; }
 }

Build lại solution và xem kết quả

codefirst_migrations_11

Qua những minh họa trên, hi vọng các bạn đã có cái nhìn rõ ràng hơn về cách migration trong EF hoạt động như thế nào, và các trường hợp sử dụng như thế nào. Chúc các bạn thành công.

Source Code mẫu: Code First Migration Demo.

One thought on “Code First Migration trong Entity Framework

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s