Code First trong Entity Framework

Code First là gì?

Entity Framework đã giới thiệu cách tiếp cận Code First trong Entity Framework 4.1. Code First chủ yếu hữu ích trong Thiết kế hướng domain.

Trong cách tiếp cận Code First, bạn tập trung vào miền của ứng dụng và bắt đầu tạo các lớp cho thực thể miền thay vì thiết kế cơ sở dữ liệu trước rồi tạo các lớp khớp với thiết kế cơ sở dữ liệu của bạn. Hình dưới đây minh họa cách tiếp cận Code First.

Code First trong Entity Framework

Như bạn có thể thấy trong hình trên, Entity Framework API sẽ tạo cơ sở dữ liệu dựa trên cấu hình và các lớp miền của bạn. Điều này có nghĩa là bạn cần bắt đầu viết code trước bằng C# hoặc VB.NET và sau đó Entity Framework (EF) sẽ tạo cơ sở dữ liệu từ code của bạn.

Quy trình làm việc với Code First

Hình dưới đây minh họa quy trình phát triển Code First.

Quy trình làm việc với Code First

Quy trình phát triển theo cách tiếp cận Code First sẽ là: Tạo hoặc sửa đổi các lớp miền -> cấu hình các lớp miền này bằng các thuộc tính chú thích dữ liệu hoặc Fluent API -> Tạo hoặc cập nhật lược đồ cơ sở dữ liệu bằng automated migration hoặc code-based migration.

Ví dụ Code First trong Entity Framework

Giả sử rằng chúng ta muốn tạo một ứng dụng đơn giản cho Trường ABC. Người dùng ứng dụng sẽ có thể thêm và cập nhật thông tin về học sinh, lớp, giáo viên và khóa học.

Thay vì thiết kế các bảng cơ sở dữ liệu trước tiên, chúng ta sẽ bắt đầu tạo các lớp cho miền. Đầu tiên, tạo các lớp StudentGrade trong đó mỗi lớp Student liên kết với một lớp Grade như ví dụ ở bên dưới. Đây được gọi là mối quan hệ một-nhiều. Tìm hiểu về cách Entity Framework quản lý mối quan hệ giữa các thực thể tại đây.

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    public Grade Grade { get; set; }
}

Tạo lớp Grade như hình dưới đây.

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Bây giờ, chúng ta đã tạo xong các lớp miền ban đầu cho ứng dụng của Trường ABC.

Cách tiếp cận Code First yêu cầu một lớp Context được kế thừa từ lớp DbContext. Tạo một lớp Context như dưới đây kế thừa từ lớp DbContext và các thuộc tính DbSet cho các lớp StudentGrade.

DbSet là một tập hợp các lớp thực thể (còn gọi là tập thực thể), vì vậy chúng tôi đã đặt tên thuộc tính là số nhiều như StudentsGrades.

namespace EF6Console
{
    public class SchoolContext: DbContext 
    {
        public SchoolContext(): base()
        { }
            
        public DbSet<Student> Students { get; set; }
        public DbSet<Grade> Grades { get; set; }
    }
}

Như vậy là chúng ta đã tạo xong các lớp cần thiết cho cách tiếp cận Code First. Bây giờ chúng ta có thể thêm một sinh viên sử dụng lớp Context như dưới đây.

namespace EF6Console
{
    class Program
    {
        static void Main(string[] args)
        {     
            using (var ctx = new SchoolContext())
            {
                var stud = new Student() 
                { 
                    StudentName = "Bill" 
                };
        
                ctx.Students.Add(stud);
                ctx.SaveChanges();                
            }
        }
    }
}

Khi chạy ứng dụng, bạn sẽ thấy một sinh viên được thêm vào cơ sở dữ liệu.

Nhưng cơ sở dữ liệu ở đâu và các bảng và cột của chúng ở đâu?

Đây là một điểm tuyệt vời của Entity Framework Code First API. Nó tạo ra cơ sở dữ liệu dựa trên tham số được truyền trong phương thức khởi tạo cơ sở của lớp Context.

Vì chúng tôi chưa truyền bất kỳ tham số nào trong phương thức khởi tạo của lớp Context, nên nó đã tạo cơ sở dữ liệu EF6Console.SchoolContext trong cơ sở dữ liệu SQLEXPRESS cục bộ, như được hiển thị trong hình bên dưới.

Nó cũng tạo ra hai bảng trong cơ sở dữ liệu này, Students và Grades dựa trên các lớp miền StudentGrade được định nghĩa ở trên.

Database được tạo bởi Code First

Như bạn có thể thấy trong hình trên, nó đã tạo các bảng Students và Grades và mỗi bảng chứa các cột có kiểu dữ liệu và độ dài thích hợp. Tên cột và kiểu dữ liệu khớp với các thuộc tính của các lớp miền tương ứng.

Nó cũng đã tạo khóa chính cho cột StudentIdGradeId và tạo khóa ngoại cho cột Grade_GradeId.

Bằng cách này, bạn không cần tạo cơ sở dữ liệu trước, bạn có thể bắt đầu viết một ứng dụng và nó sẽ tạo cơ sở dữ liệu từ các lớp miền của bạn.

Lưu ý: Nếu bạn sửa đổi các lớp này và chạy lại ứng dụng, thì nó sẽ ném ngoại lệ sau.
Ngoại lệ trong Code First

Bạn cần chỉ định chiến lược khởi tạo cơ sở dữ liệu trong lớp Context để sửa đổi các lớp miền và chạy ứng dụng cục bộ. Chiến lược khởi tạo cơ sở dữ liệu sẽ được trình bày chi tiết ở một bài viết khác.

Bạn có thắc mắc làm thế nào nó tạo ra cơ sở dữ liệu có các bảng, các cột với kiểu dữ liệu và độ dài thích hợp, khóa chính, khóa ngoại không? Câu trả lời là sử dụng các quy ước trong Code First.

Các quy ước trong Code First

Các quy ước là các bộ quy tắc mặc định tự động cấu hình một mô hình khái niệm dựa trên các lớp miền của bạn khi làm việc với cách tiếp cận Code First.

Như bạn đã thấy trong ví dụ ở trên, Entity Framework API đã cấu hình các khóa chính, khóa ngoại, các mối quan hệ, kiểu dữ liệu của cột, v.v. từ các lớp miền mà không cần cấu hình bổ sung.

Điều này là do các quy ước của Entity Framework Code First. Nếu các lớp miền của bạn tuân theo các quy ước thì lược đồ cơ sở dữ liệu sẽ được cấu hình dựa trên các quy ước này.

Các quy ước trong Entity Framework 6.x Code First được định nghĩa trong namespace System.Data.Entity.ModelConfiguration.Conventions .

Bảng sau liệt kê các quy ước mặc định của Code First:

Quy ước Miêu tả
Lược đồ Theo mặc định, EF tạo tất cả các đối tượng DB vào lược đồ dbo .
Tên bảng <Tên lớp thực thể> + 's'
EF sẽ tạo bảng DB với tên lớp thực thể thêm 's' ở cuối, ví dụ: lớp Student sẽ ánh xạ tới bảng Students.
Tên khóa chính 1) Id
2) <Tên lớp thực thể> + "Id" (không phân biệt chữ hoa chữ thường)

EF sẽ tạo cột khóa chính cho thuộc tính có tên Id hoặc <Tên lớp thực thể> + "Id" (không phân biệt chữ hoa chữ thường).
Tên khóa ngoại Theo mặc định, EF sẽ tìm thuộc tính khóa ngoại có cùng tên với tên khóa chính của thực thể chính.
Nếu thuộc tính khóa ngoại không tồn tại, thì EF sẽ tạo cột khóa ngoại trong bảng Db với <Tên thuộc tính điều hướng> + "_" + <Tên thuộc tính khóa chính của thực thể chính>
ví dụ: EF sẽ tạo cột khóa ngoại Grade_GradeId trong bảng Students nếu thực thể Student không chứa thuộc tính khóa ngoại cho Grade.
Cột Null EF tạo một cột null cho tất cả các thuộc tính kiểu tham chiếu và các thuộc tính kiểu nguyên thủy nullable, ví dụ: string, Nullable <int>, Student, Grade (tất cả các thuộc tính kiểu lớp)
Cột Not Null EF tạo các cột Not Null cho các thuộc tính khóa chính và các thuộc tính kiểu giá trị không nullable, ví dụ: int, float, binary, datetime, v.v.
Thứ tự cột EF sẽ tạo các cột theo cùng thứ tự như các thuộc tính trong một lớp thực thể. Tuy nhiên, các cột khóa chính sẽ được di chuyển lên đầu tiên.
Ánh xạ thuộc tính vào DB Theo mặc định, tất cả các thuộc tính sẽ ánh xạ tới cơ sở dữ liệu. Sử dụng thuộc tính [NotMapped] để loại trừ thuộc tính hoặc lớp không ánh xạ vào DB.
Cascade delete Được bật theo mặc định cho tất cả các loại mối quan hệ.

Bảng sau liệt kê kiểu dữ liệu C# được ánh xạ với kiểu dữ liệu SQL Server.

Kiểu dữ liệu C# Ánh xạ tới kiểu dữ liệu SQL Server
int int
string nvarchar(Max)
decimal decimal(18,2)
float real
byte[] varbinary(Max)
datetime datetime
bool bit
byte tinyint
short smallint
long bigint
double float
char Không ánh xạ
sbyte Không ánh xạ (ném ra exception)
object Không ánh xạ

Hình dưới đây minh họa ánh xạ quy ước với cơ sở dữ liệu.

Các quy ước trong Code First

Quy ước về mối quan hệ

Entity Framework 6 tạo mối quan hệ một-nhiều bằng cách sử dụng thuộc tính điều hướng theo quy ước mặc định. Phần này sẽ được trình bày chi tiết trong bài viết khác.

Lưu ý: Entity Framework 6 không có các quy ước mặc định cho các mối quan hệ một-một và nhiều-nhiều. Bạn cần cấu hình chúng bằng Fluent API hoặc DataAnnotation.

Quy ước kiểu phức tạp

Code First tạo kiểu phức tạp cho lớp không bao gồm thuộc tính khóa và khóa chính không được đăng ký bằng thuộc tính DataAnnotation hoặc Fluent API.

Phần này trình bày tổng quan về các quy ước trong Code First. Các quy ước này có thể được ghi đè bằng các sử dụng thuộc tính DataAnnotation hoặc Fluent API.



Bài viết liên quan:

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.

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 có gì mới? Truy vấn trong EF Core khác EF ở những điểm nào.