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:

  1. Migration tự động.
  2. 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-migrationsget-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:

  1. 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.
  2. 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()Down().
  3. 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).

Migration dựa trên mã trong EF Code First

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()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

Entity Framework
Bài Viết Liên Quan:
2 kịch bản lưu dữ liệu trong Entity Framework Core
Trung Nguyen 30/04/2020
2 kịch bản lưu dữ liệu trong Entity Framework Core

2 kịch bản lưu dữ liệu trong Entity Framework Core là kịch bản được kết nối và kịch bản ngắt kết nối.

Ứng dụng Entity Framework Core đầu tiên
Trung Nguyen 29/04/2020
Ứng dụng Entity Framework Core đầu tiên

Tạo ứng dụng .NET Core Console đầu tiên và cấu hình sử dụng Entity Framework Core.

Truy vấn trong Entity Framework Core
Trung Nguyen 29/04/2020
Truy vấn trong Entity Framework Core

Truy vấn trong Entity Framework Core có gì mới? Truy vấn trong EF Core khác EF ở những điểm nào.

Entity Framework Core toàn tập
Trung Nguyen 29/04/2020
Entity Framework Core toàn tập

Entity Framework Core toàn tập sẽ hướng dẫn bạn tất cả mọi thứ về Entity Framework Core.