Migration trong Entity Framework
Entity Framework Code First có các chiến lược khởi tạo cơ sở dữ liệu khác nhau như CreateDatabaseIfNotExists
, DropCreateDatabaseIfModelChanges
, và DropCreateDatabaseAlways
.
Tuy nhiên, có một số vấn đề với các chiến lược này, ví dụ: nếu bạn đã có dữ liệu (trừ seed data – dữ liệu ban đầu được thêm bằng code) hoặc stored procedures, triggers, v.v. trong cơ sở dữ liệu của bạn.
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ó, do đó bạn sẽ mất dữ liệu và các đối tượng DB khác.
Entity Framework đã giới thiệu một công cụ migration tự động cập nhật lược đồ cơ sở dữ liệu khi mô hình của bạn thay đổi mà không mất bất kỳ dữ liệu hiện có 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 gọi là MigrateDatabaseToLatestVersion
.
Có hai loại Migration:
- Migration tự động.
- Migration dựa trên mã.
Migration tự động trong Entity Framework
Entity Framework đã giới thiệu Migration tự động để bạn không phải xử lý di chuyển cơ sở dữ liệu theo cách thủ công cho mỗi thay đổi bạn thực hiện trong các lớp thực thể của mình.
Việc Migration tự động có thể được thực hiện bằng cách thực hiện lệnh enable-migrations
trong Package Manager Console.
Mở Package Manager Console bằng cách truy cập menu Tools → Library Package Manager → Package Manager Console và sau đó chạy lệnh enable-migrations –EnableAutomaticMigration:$true
.
Lưu ý: bạn phải chọn project chứa lớp Context của bạn khi chạy lệnh trên.

Khi lệnh chạy thành công, nó sẽ tạo một lớp Configuration
có nguồn gốc từ lớp DbMigrationConfiguration
trong thư mục Migration trong dự án của bạn:

Như bạn có thể thấy trong phương thức khởi tạo của lớp Configuration
, thuộc tính AutomaticMigrationsEnabled
được thiết lập thành true.
Bước tiếp theo là thiết lập trình khởi tạo cơ sở dữ liệu trong lớp Context thành MigrateDatabaseToLatestVersion
, như ví dụ bên dưới.
public class SchoolContext: DbContext
{
public SchoolDBContext(): base("SchoolDB")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SchoolDBContext, EF6Console.Migrations.Configuration>());
}
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Như vậy là bạn đã thiết lập xong cho migration tự động. EF sẽ tự động đảm nhiệm việc di chuyển khi bạn thay đổi các lớp thực thể.
Đến lúc này, chúng tôi chỉ có lớp thực thể Student
trong lớp SchoolContext
ở trên. Chạy ứng dụng và xem cơ sở dữ liệu đã được tạo như hình sau:

Bạn sẽ thấy rằng EF API đã tạo một bảng hệ thống __MigrationHistory
cùng với bảng Students
. Bảng __MigrationHistory
chứa lịch sử thay đổi cơ sở dữ liệu cho tất cả những lần di chuyển.
Bây giờ, bạn có thể thêm các lớp thực thể mới và khi bạn chạy lại ứng dụng bạn sẽ thấy rằng cơ sở dữ liệu có các bảng cho tất cả các thực thể. Bạn không cần phải chạy bất kỳ lệnh nào.
Tuy nhiên, điều này chỉ hoạt động nếu bạn thêm các lớp thực thể mới hoặc xóa các lớp thực thể. Nó sẽ không hoạt động khi bạn thêm, sửa đổi hoặc xóa các thuộc tính trong các lớp thực thể.
Để kiểm tra điều này, bạn thử xóa bất kỳ thuộc tính nào khỏi lớp thực thể và chạy ứng dụng. Bạn sẽ nhận được ngoại lệ sau đây.

Điều này là do bạn sẽ mất dữ liệu trong cột tương ứng của thuộc tính trong lớp thực thể. Vì vậy, để xử lý loại kịch bản này, bạn phải thiết lập giá trị của thuộc tính AutomaticMigrationDataLossAllowed
thành true trong phương thức khởi tạo của lớp Configuration
, cùng với AutomaticMigrationsEnabled = true;
.
Để biết thêm về các tham số của lệnh enable-migrations
, bạn có thể chạy lệnh get-help enable-migrations
và get-help enable-migrations -detailed
trong Package Manager Console, như ví dụ bên dưới.
PM> get-help enable-migrations
NAME
Enable-Migrations
SYNOPSIS
Enables Code First Migrations in a project.
SYNTAX
Enable-Migrations [-ContextTypeName <String>] [-EnableAutomaticMigrations]
[-MigrationsDirectory <String>] [-ProjectName <String>] [-StartUpProjectName
<String>] [-ContextProjectName <String>] [-ConnectionStringName <String>]
[-Force] [-ContextAssemblyName <String>] [-AppDomainBaseDirectory <String>]
[<CommonParameters>]
Enable-Migrations [-ContextTypeName <String>] [-EnableAutomaticMigrations]
[-MigrationsDirectory <String>] [-ProjectName <String>] [-StartUpProjectName
<String>] [-ContextProjectName <String>] -ConnectionString <String>
-ConnectionProviderName <String> [-Force] [-ContextAssemblyName <String>]
[-AppDomainBaseDirectory <String>] [<CommonParameters>]
DESCRIPTION
Enables Migrations by scaffolding a migrations configuration class in the project. If the
target database was created by an initializer, an initial migration will be created (unless
automatic migrations are enabled via the EnableAutomaticMigrations parameter).
RELATED LINKS
REMARKS
To see the examples, type: "get-help Enable-Migrations -examples".
For more information, type: "get-help Enable-Migrations -detailed".
For technical information, type: "get-help Enable-Migrations -full".
Migration dựa trên mã trong Entity Framework
Trong phần trước, bạn đã tìm hiểu về Migration tự động trong Entity Framework tự động cập nhật lược đồ cơ sở dữ liệu khi bạn thay đổi các lớp thực thể. Ở phần này, bạn sẽ tìm hiểu về Migration dựa trên mã.
Migration dựa trên mã cung cấp thêm quyền kiểm soát đối với việc di chuyển và cho phép bạn cấu hình những thứ bổ sung như thiết lập giá trị mặc định của cột, cấu hình cột được tính toán, v.v.
Để sử dụng Migration dựa trên mã, bạn cần thực hiện các lệnh sau trong Package Manager Console trong Visual Studio:
- Enable-Migrations: Cho phép di chuyển trong dự án của bạn bằng cách tạo một lớp
Configuration
. - Add-Migration: Tạo một lớp di chuyển mới theo tên được chỉ định với các phương thức
Up()
vàDown()
. - Update-Database: Thực thi file di chuyển cuối cùng được tạo bởi lệnh
Add-Migration
và áp dụng các thay đổi cho lược đồ cơ sở dữ liệu.
Để sử dụng Migration dựa trên mã, trước tiên hãy thực thi lệnh enable-migrations
trong Package Manager Console. Mở Package Manager Console từ menu Tools → Library Package Manager → Package Manager Console và sau đó chạy lệnh enable-migrations
(đảm bảo rằng dự án mặc định là dự án có lớp Context của bạn).

Lệnh Enable-Migrations
sẽ tạo ra lớp Configuration
có nguồn gốc từ DbMigrationsConfiguration
với AutomaticMigrationsEnabled = false
.
Bây giờ, bạn cần thiết lập trình khởi tạo cơ sở dữ liệu MigrateDatabaseToLatestVersion
trong lớp Context của mình, như ví dụ bên dưới.
public class SchoolContext: DbContext
{
public SchoolDBContext(): base("SchoolDB")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SchoolDBContext, EF6Console.Migrations.Configuration>());
}
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
Bây giờ, bạn phải tạo một lớp Migration bằng cách sử dụng lệnh Add-Migration
với tên của lớp Migration của bạn, như được hiển thị bên dưới.

Lệnh trên sẽ tạo một file có tên <timestamp>_SchoolDB-v1.cs
có các phương thức Up()
và Down()
, như hiển thị bên dưới.

Như bạn có thể thấy, phương thức Up()
chứa mã để tạo các đối tượng cơ sở dữ liệu và phương thức Down()
chứa mã để loại bỏ hoặc xóa các đối tượng cơ sở dữ liệu.
Bạn cũng có thể viết mã tùy chỉnh của riêng bạn cho các cấu hình bổ sung. Đây là lợi thế so với Migration tự động.
Để biết thêm về các tham số lệnh add-migration
, thực thi các lệnh get-help add-migration
hoặc get-help add-migration -detailed
trong Package Manager Console, như hiển thị bên dưới.
PM> get-help add-migration
NAME
Add-Migration
SYNOPSIS
Scaffolds a migration script for any pending model changes.
SYNTAX
Add-Migration [-Name] <String> [-Force] [-ProjectName <String>] [-StartUpProjectName <String>]
[-ConfigurationTypeName <String>] [-ConnectionStringName <String>] [-IgnoreChanges]
[-AppDomainBaseDirectory <String>] [<CommonParameters>]
Add-Migration [-Name] <String> [-Force] [-ProjectName <String>] [-StartUpProjectName <String>]
[-ConfigurationTypeName <String>] -ConnectionString <String> -ConnectionProviderName <String>
[-IgnoreChanges] [-AppDomainBaseDirectory <String>] [<CommonParameters>]
DESCRIPTION
Scaffolds a new migration script and adds it to the project.
RELATED LINKS
REMARKS
To see the examples, type: "get-help Add-Migration -examples".
For more information, type: "get-help Add-Migration -detailed".
For technical information, type: "get-help Add-Migration -full".
Sau khi tạo file Migration bằng lệnh add-migration, bạn phải cập nhật cơ sở dữ liệu.
Thực thi lệnh Update-Database
để tạo hoặc sửa đổi một lược đồ cơ sở dữ liệu. Sử dụng tùy chọn –verbose
để xem các câu lệnh SQL đang được áp dụng cho cơ sở dữ liệu đích.

Thực thi lệnh get-help update-database
hoặc get-help update-database -detailed
trong Package Manager Console để biết thêm về lệnh.
PM> get-help update-database
NAME
Update-Database
SYNOPSIS
Applies any pending migrations to the database.
SYNTAX
Update-Database [-SourceMigration <String>] [-TargetMigration <String>] [-Script] [-Force]
[-ProjectName <String>] [-StartUpProjectName <String>] [-ConfigurationTypeName <String>]
[-ConnectionStringName <String>] [-AppDomainBaseDirectory <String>] [<CommonParameters>]
Update-Database [-SourceMigration <String>] [-TargetMigration <String>] [-Script] [-Force]
[-ProjectName <String>] [-StartUpProjectName <String>] [-ConfigurationTypeName <String>]
-ConnectionString <String> -ConnectionProviderName <String> [-AppDomainBaseDirectory <String>]
[<CommonParameters>]
DESCRIPTION
Updates the database to the current model by applying pending migrations.
RELATED LINKS
REMARKS
To see the examples, type: "get-help Update-Database -examples".
For more information, type: "get-help Update-Database -detailed".
For technical information, type: "get-help Update-Database -full".
Tại thời điểm này, cơ sở dữ liệu sẽ được tạo hoặc cập nhật. Bây giờ, bất cứ khi nào bạn thay đổi các lớp thực thể, hãy thực thi lệnh Add-Migration
với tham số name để tạo file Migration mới và sau đó thực hiện lệnh Update-Database
để áp dụng các thay đổi cho lược đồ cơ sở dữ liệu.
Rollback Migration
Giả sử bạn muốn khôi phục lược đồ cơ sở dữ liệu về bất kỳ trạng thái nào trước đó, thì bạn có thể thực thi lệnh update-database
với tham số –TargetMigration
đến điểm mà bạn muốn quay lại.
Ví dụ: giả sử có nhiều lần Migration được áp dụng cho cơ sở dữ liệu SchoolDB ở trên nhưng bạn muốn quay lại lần di chuyển đầu tiên. Thì thực hiện lệnh sau.
PM> update-database -TargetMigration:SchoolDB-v1