Attribute chú thích dữ liệu trong Entity Framework

Attribute (thuộc tính) chú thích dữ liệu là các thuộc tính .NET có thể được áp dụng trên một lớp thực thể hoặc thuộc tính để ghi đè các quy ước mặc định trong EF 6 và EF Core.

Các attribute chú thích dữ liệu có trong namespace System. ComponentModel. DataAnnotationsSystem. ComponentModel. DataAnnotations. Schema trong EF 6 cũng như trong EF Core.

Các thuộc tính này không chỉ được sử dụng trong Entity Framework mà chúng còn có thể được sử dụng trong ASP.NET WebForm và ASP.NET MVC hoặc các điều khiển dữ liệu.

Các attribute chú thích dữ liệu này hoạt động theo cùng một cách trong EF 6 và EF Core và có giá trị trong cả hai.

Lưu ý: Chú thích dữ liệu chỉ cung cấp cho bạn một tập hợp con các tùy chọn cấu hình. Fluent API cung cấp một bộ đầy đủ các tùy chọn cấu hình có sẵn trong Code-First.

Các attribute chú thích dữ liệu

Các attribute chú thích dữ liệu của namespace System. ComponentModel. DataAnnotations

Attribute Mô tả
Key Có thể được áp dụng cho một thuộc tính để chỉ định một thuộc tính khóa trong một thực thể và biến cột tương ứng thành cột khóa chính trong cơ sở dữ liệu.
Timestamp Có thể được áp dụng cho một thuộc tính để chỉ định kiểu dữ liệu của một cột tương ứng trong cơ sở dữ liệu như rowversion.
ConcurrencyCheck Có thể được áp dụng cho một thuộc tính để chỉ định rằng cột tương ứng phải được đưa vào kiểm tra concurrency.
Required Có thể được áp dụng cho một thuộc tính để chỉ định rằng cột tương ứng là cột NotNull trong cơ sở dữ liệu.
MinLength Có thể được áp dụng cho một thuộc tính để chỉ định độ dài chuỗi tối thiểu được phép của cột tương ứng trong cơ sở dữ liệu.
MaxLength Có thể được áp dụng cho một thuộc tính để chỉ định độ dài chuỗi tối đa được phép của cột tương ứng trong cơ sở dữ liệu.
StringLength Có thể được áp dụng cho một thuộc tính để chỉ định độ dài chuỗi tối đa được phép của cột tương ứng trong cơ sở dữ liệu.

Các attribute chú thích dữ liệu của namespace System. ComponentModel. DataAnnotations. Schema

Attribute Mô tả
Table Có thể được áp dụng cho một lớp thực thể để cấu hình tên bảng và lược đồ tương ứng trong cơ sở dữ liệu.
Column Có thể được áp dụng cho một thuộc tính để cấu hình tên cột, thứ tự và kiểu dữ liệu tương ứng trong cơ sở dữ liệu.
Index Có thể được áp dụng cho một thuộc tính để cấu hình rằng cột tương ứng sẽ có một Index trong cơ sở dữ liệu. (Chỉ từ EF 6.1 trở đi)
ForeignKey Có thể được áp dụng cho một thuộc tính để đánh dấu nó là một thuộc tính khóa ngoại.
NotMapped Có thể được áp dụng cho một thuộc tính hoặc lớp thực thể cần được loại trừ khỏi mô hình và không nên tạo một cột hoặc bảng tương ứng trong cơ sở dữ liệu.
DatabaseGenerated Có thể được áp dụng cho một thuộc tính để cấu hình cách cơ sở dữ liệu cơ sở sẽ tạo giá trị cho cột tương ứng, ví dụ: identity, computed hoặc none.
InverseProperty Có thể được áp dụng cho một thuộc tính để chỉ định nghịch đảo của thuộc tính điều hướng đại diện cho đầu kia của cùng một mối quan hệ.
ComplexType Đánh dấu lớp là kiểu phức tạp trong EF 6. EF Core 2.0 không hỗ trợ thuộc tính này.

Table Attribute trong Entity Framework

Thuộc tính Table (Table Attribute) có thể được áp dụng cho một lớp để cấu hình tên bảng tương ứng trong cơ sở dữ liệu. Nó ghi đè lên quy ước mặc định trong EF 6 và EF Core.

Theo các quy ước mặc định, EF 6 tạo một tên bảng khớp với tên thuộc tính (DbSet<TEntity> PropertyName + 's' hoặc 'es') trong lớp Context.

Khai báo thuộc tính Table:


[Table(string name, Properties:[Schema = string])]
  • name: Tên của bảng trong Db.
  • schema: Tên của Lược đồ Db trong đó một bảng được chỉ định sẽ được tạo. (Không bắt buộc)

using System.ComponentModel.DataAnnotations.Schema;

[Table("StudentMaster")]
public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
}

Trong ví dụ trên, thuộc tính Table được áp dụng cho lớp thực thể Student. Vì vậy, EF sẽ ghi đè các quy ước mặc định và tạo bảng StudentMaster thay vì bảng Students trong cơ sở dữ liệu, như được hiển thị bên dưới.

Table Attribute trong Entity Framework

Sử dụng thuộc tính Schema để chỉ định tên lược đồ cho bảng trong Db như dưới đây.


using System.ComponentModel.DataAnnotations.Schema;

[Table("StudentMaster", Schema="Admin")]
public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
}

EF sẽ tạo bảng StudentMaster trong lược đồ Admin như dưới đây.

Table Attribute trong Entity Framework

Column Attribute trong Entity Framework

Thuộc tính Column (Column Attribute) có thể được áp dụng cho một hoặc nhiều thuộc tính trong lớp thực thể để định cấu hình tên cột, kiểu dữ liệu và thứ tự tương ứng trong bảng cơ sở dữ liệu.

Thuộc tính Column ghi đè quy ước mặc định. Theo các quy ước mặc định trong EF 6 và EF Core, nó tạo một cột trong bảng db có cùng tên và thứ tự như tên thuộc tính.

Khai báo thuộc tính Column:


[Column(string name, Properties:[Order = int],[TypeName = string])]
  • name: Tên của một cột trong bảng db.
  • Order: Thứ tự của một cột, bắt đầu với chỉ số bằng 0. (Không bắt buộc)
  • TypeName: Kiểu dữ liệu của một cột. (Không bắt buộc)

Ví dụ sau đây thay đổi tên của một cột.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
     
    [Column("Name")]
    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; }
}

Trong ví dụ trên, thuộc tính Column được áp dụng cho một thuộc tính StudentName. Vì vậy, EF sẽ ghi đè các quy ước mặc định và tạo một cột Name thay vì cột StudentName trong bảng Students như dưới đây.

Column Attribute trong Entity Framework

Kiểu dữ liệu của cột

Sử dụng tham số TypeName trong thuộc tính Column để thay đổi kiểu dữ liệu phù hợp của cột db tương ứng, như được trình bảy ở bên dưới.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    
    [Column("Name")]
    public string StudentName { get; set; }
    [Column("DoB", TypeName="DateTime2")]
    public DateTime DateOfBirth { get; set; }
    public byte[] Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
}

Trong ví dụ trên, tham số TypeName = "DateTime2" được áp dụng trên thuộc tính DateOfBirth. Điều này sẽ tạo ra một cột kiểu DateTime2 thay vì DateTime như dưới đây.

Column Attribute trong Entity Framework

Thứ tự cột

Sử dụng tham số Order bắt đầu từ 0 để thiết lập thứ tự các cột trong cơ sở dữ liệu.

Theo quy ước mặc định, các cột khóa chính sẽ đứng trước và sau đó là các cột còn lại dựa trên thứ tự các thuộc tính tương ứng của chúng trong một lớp thực thể.

Lưu ý: Tham số Order phải được áp dụng trên tất cả các thuộc tính có chỉ số khác nhau, bắt đầu từ số 0.

using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    [Column(Order = 0)]
    public int StudentID { get; set; }
    
    [Column("Name", Order = 1)]
    public string StudentName { get; set; }
    
    [Column("DoB", Order = 5)]
    public DateTime DateOfBirth { get; set; }
    [Column(Order = 3)]
    public byte[] Photo { get; set; }
    [Column(Order = 2)]
    public decimal Height { get; set; }
    [Column(Order = 4)]
    public float Weight { get; set; }
}

Ví dụ trên sẽ tạo các cột theo thứ tự được chỉ định như dưới đây.

Column Attribute trong Entity Framework

Key Attribute trong Entity Framework

Thuộc tính Key (Key Attribute) có thể được áp dụng cho một thuộc tính trong lớp thực thể để biến nó thành thuộc tính khóa và cột tương ứng với cột khóa chính trong cơ sở dữ liệu.

Quy ước mặc định tạo một cột khóa chính cho một thuộc tính có tên là Id hoặc <Entity Class Name>Id. Thuộc tính Key ghi đè quy ước mặc định này.


using System.ComponentModel.DataAnnotations;

public class Student
{
    [Key]
    public int StudentKey { get; set; }
    public string StudentName { get; set; }
}

Như bạn có thể thấy trong ví dụ trên, thuộc tính Key được áp dụng cho thuộc tính StudentKey của lớp thực thể Student.

Điều này sẽ ghi đè các quy ước mặc định và tạo một cột khóa chính là StudentKey trong bảng Students trong cơ sở dữ liệu như dưới đây.

Key Attribute trong Entity Framework

Thuộc tính Key có thể được áp dụng cho một thuộc tính của bất kỳ kiểu dữ liệu nguyên thủy nào ngoại trừ kiểu số nguyên không dấu.

Key Attribute trong EF 6:

Trong EF 6, thuộc tính Key cùng với thuộc tính Column có thể được áp dụng cho nhiều thuộc tính của một lớp thực thể sẽ tạo các cột khóa chính tổng hợp trong cơ sở dữ liệu.


using System.ComponentModel.DataAnnotations;

public class Student
{
    [Key]
    [Column(Order=1)]
    public int StudentKey { get; set; }
     
    [Key]
    [Column(Order=2)]
    public int AdmissionNum { get; set; }
     
    public string StudentName { get; set; }
}

Đoạn mã trên tạo các cột khóa chính tổng hợp StudentKeyAdmissionNum trong bảng Students như dưới đây.

Key Attribute trong Entity Framework
Lưu ý: Trong EF 6, thuộc tính Key tạo khóa chính là một cột identity khi được áp dụng cho một thuộc tính kiểu số nguyên. Khóa tổng hợp không tạo cột identity cho thuộc tính kiểu số nguyên.

NotMapped Attribute trong Entity Framework

Thuộc tính NotMapped (NotMapped Attribute) có thể được áp dụng cho các thuộc tính của lớp thực thể mà chúng ta không muốn tạo các cột tương ứng trong cơ sở dữ liệu.

Theo mặc định, EF tạo một cột cho mỗi thuộc tính (phải có get; và set;) trong một lớp thực thể. Thuộc tính NotMapped ghi đè quy ước mặc định này.

Bạn có thể áp dụng thuộc tính NotMapped trên một hoặc nhiều thuộc tính mà bạn KHÔNG muốn tạo cột tương ứng trong bảng cơ sở dữ liệu.

Khai báo thuộc tính NotMaps: [NotMapped]


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
        
    [NotMapped]
    public int Age { get; set; }
}

Trong ví dụ trên, thuộc tính NotMapped được áp dụng cho thuộc tính Age của lớp Student. Vì vậy, EF sẽ không tạo một cột để lưu trữ thông tin Age trong bảng db Students, như được hiển thị bên dưới.

NotMapped Attribute trong Entity Framework
Lưu ý: EF cũng không tạo cột cho thuộc tính không có getters hoặc setters (thuộc tính chỉ đọc hoặc chỉ ghi). Ví dụ, EF sẽ không tạo các cột cho các thuộc tính CityAge.

using System.ComponentModel.DataAnnotations;

public class Student
{
    private int _age = 0;

    public int StudentId { get; set; }
    public string StudentName { get; set; }
    public string City { get{ return StudentName;}  }
    public int Age { set{ _age = value;}  }
}

ForeignKey Attribute trong Entity Framework

Thuộc tính ForeignKey (ForeignKey Attribute) được sử dụng để cấu hình khóa ngoại trong mối quan hệ giữa hai thực thể trong EF 6 và EF Core.

Nó ghi đè các quy ước mặc định. Theo quy ước mặc định, EF tạo một thuộc tính là thuộc tính khóa ngoài khi tên của nó khớp với thuộc tính khóa chính của một thực thể có liên quan.

Khai báo thuộc tính ForeignKey: [ForeignKey(name string)]

  • name: Tên của thuộc tính điều hướng được liên kết hoặc tên của (các) khóa ngoại được liên kết.

Hãy xem ví dụ sau đây về mối quan hệ một-nhiều giữa các thực thể.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    //Foreign key for Standard
    public int StandardId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Ví dụ trên mô tả mối quan hệ một-nhiều giữa các thực thể StudentStandard. Để thể hiện mối quan hệ này, lớp Student bao gồm một thuộc tính StandardId có thuộc tính tham chiếu Standard và lớp thực thể Standard bao gồm thuộc tính điều hướng danh sách Students.

Tên thuộc tính StandardId trong thực thể Student khớp với thuộc tính khóa chính của thực thể Standard. Do đó, thuộc tính StandardId trong thực thể Student sẽ tự động trở thành thuộc tính khóa ngoài và cột tương ứng trong bảng db cũng sẽ là cột khóa ngoài, như được hiển thị bên dưới.

ForeignKey Attribute trong Entity Framework

Thuộc tính ForeignKey ghi đè các quy ước mặc định cho một khóa ngoại. Nó cho phép chúng ta chỉ định thuộc tính khóa ngoại trong thực thể phụ thuộc có tên không phù hợp với thuộc tính khóa chính của thực thể chính.

Thuộc tính ForeignKey có thể được áp dụng theo ba cách:

  1. Khai báo [ForeignKey(NavigationPropertyName)] trên thuộc tính khóa ngoại trong thực thể phụ thuộc.
  2. Khai báo [ForeignKey(ForeignKeyPropertyName)] trên thuộc tính điều hướng tham chiếu có liên quan trong thực thể phụ thuộc.
  3. Khai báo [ForeignKey(ForeignKeyPropertyName)] trên thuộc tính điều hướng trong thực thể chính.

ForeignKey Attribute trên thuộc tính khóa ngoại trong thực thể phụ thuộc

Khai báo ForeignKey trên thuộc tính khóa ngoại trong thực thể phụ thuộc và tên thuộc tính định vị liên quan được khai báo như một tham số như dưới đây.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    [ForeignKey("Standard")]
    public int StandardRefId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Trong ví dụ trên, thuộc tính ForeignKey được áp dụng trên thuộc tính StandardRefId và chỉ định tên của thuộc tính điều hướng là Standard.

Điều này sẽ tạo cột khóa ngoại có tên StandardRefId trong bảng Students, ngăn chặn việc tạo cột StandardId trong cơ sở dữ liệu.

ForeignKey Attribute trong Entity Framework

ForeignKey Attribute trên thuộc tính điều hướng trong thực thể phụ thuộc

Thuộc tính ForeignKey có thể được áp dụng cho thuộc tính chuyển hướng và tên thuộc tính khóa ngoại liên quan được khai báo như dưới đây.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public int StandardRefId { get; set; }
    
    [ForeignKey("StandardRefId")]
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Trong ví dụ trên, thuộc tính ForeignKey được áp dụng trên thuộc tính điều hướng Standard và chỉ định tên của thuộc tính khóa ngoại là StandardRefId.

Điều này sẽ tạo cột khóa ngoại có tên StandardRefId trong bảng Students, ngăn chặn việc tạo cột StandardId trong cơ sở dữ liệu.

ForeignKey Attribute trên thuộc tính điều hướng trong thực thể chính

Thuộc tính ForeignKey có thể được áp dụng cho thuộc tính chuyển hướng trong thực thể chính và chỉ định tên thuộc tính khóa ngoại của thực thể phụ thuộc, như dưới đây.


using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    public int StandardRefId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    [ForeignKey("StandardRefId")]
    public ICollection<Student> Students { get; set; }
}

Trong ví dụ trên, thuộc tính ForeignKey được áp dụng trên thuộc tính điều hướng Students trong thực thể chính Standard. Điều này sẽ tạo ra một cột khóa ngoại StandardRefId trong bảng Students trong cơ sở dữ liệu.

Index Attribute trong Entity Framework

Entity Framework 6 cung cấp thuộc tính Index (Index Attribute) để tạo một index trên một cột cụ thể trong cơ sở dữ liệu, như được trình bày bên dưới:


class Student
{
    public int Student_ID { get; set; }
    public string StudentName { get; set; }
        
    [Index]
    public int RegistrationNumber { get; set; }
}

Theo mặc định, tên index sẽ là IX_{property name}. Tuy nhiên, bạn có thể thay đổi tên của index.

Ngoài ra bạn cũng có thể biến nó thành một clustered index bằng cách chỉ định IsClustered = true hoặc tạo một unique index bằng cách chỉ định IsUnique=true.


[Index("INDEX_REGNUM", IsClustered=true, IsUnique=true)]
public int RegistrationNumber { get; set; }

InverseProperty Attribute trong Entity Framework

Thuộc tính InverseProperty (InverseProperty Attribute) được sử dụng khi hai thực thể có nhiều hơn một mối quan hệ. Để hiểu thuộc tính InverseProperty, hãy xem ví dụ thực thể CourseTeacher sau đây.


public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
}

Trong ví dụ trên, các thực thể CourseTeacher có mối quan hệ một-nhiều trong đó một giáo viên có thể dạy nhiều khóa học khác nhau.

Theo các quy ước mặc định trong EF 6 và EF Core, ví dụ trên sẽ tạo các bảng sau trong cơ sở dữ liệu.

InverseProperty Attribute trong Entity Framework

Bây giờ, giả sử chúng ta thêm một mối quan hệ một-nhiều giữa các thực thể TeacherCourse như sau.


public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    public ICollection<Course> OnlineCourses { get; set; }
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Trong ví dụ trên, các thực thể CourseTeacher có hai mối quan hệ một-nhiều. Một khóa học có thể được dạy bởi một giáo viên trực tuyến hoặc một giáo viên trên lớp.

Theo cùng cách trên, một giáo viên cũng có thể dạy nhiều khóa học trực tuyến hoặc nhiều khóa học trên lớp.

Ở trường hợp này, EF API không thể xác định đầu kia của mối quan hệ. Nó sẽ đưa ra ngoại lệ sau đây cho ví dụ trên trong quá trình migration.

Unable to determine the relationship represented by navigation property 'Course.OnlineTeacher' of type 'Teacher'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Tuy nhiên, EF 6 sẽ tạo bảng Courses sau với bốn khóa ngoại như sau:

InverseProperty Attribute trong Entity Framework

Để giải quyết vấn đề này, sử dụng thuộc tính InverseProperty để định cấu hình đầu kia của mối quan hệ như dưới đây.


public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public Teacher OnlineTeacher { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Trong ví dụ trên, thuộc tính InverseProperty được áp dụng trên hai thuộc tính điều hướng OnlineCoursesClassRoomCourses để chỉ định thuộc tính điều hướng liên quan của chúng trong thực thể Course.

Vì vậy, bây giờ EF có thể tìm ra tên khóa ngoại tương ứng. EF 6 tạo khóa ngoại OnlineTeacher_TeacherIdClassRoomTeacher_TeacherId cho bảng Courses như sau:

InverseProperty Attribute trong Entity Framework

Bạn có thể sử dụng thuộc tính ForeignKey để cấu hình tên khóa ngoại như bên dưới.


public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    [ForeignKey("OnlineTeacher")]
    public int? OnlineTeacherId { get; set; }
    public Teacher OnlineTeacher { get; set; }

    [ForeignKey("ClassRoomTeacher")]
    public int? ClassRoomTeacherId { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}

Ví dụ trên sẽ dẫn đến các bảng sau trong cơ sở dữ liệu.

InverseProperty Attribute trong Entity Framework

Do đó, bạn có thể sử dụng các thuộc tính InversePropertyForeignKey để cấu hình nhiều mối quan hệ trên cùng các thực thể.

Required Attribute trong Entity Framework

Thuộc tính Required (Required Attribute) có thể áp dụng cho một hoặc nhiều thuộc tính trong một lớp thực thể. EF sẽ tạo một cột NOT NULL trong bảng cơ sở dữ liệu cho thuộc tính có khai báo attribute Required.


using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public int StudentID { get; set; }
    [Required]
    public string StudentName { get; set; }
}

Trong đoạn mã trên, thuộc tính Required áp dụng cho thuộc tính StudentName. Vì vậy, EF API sẽ tạo một cột StudentName NOT NULL trong bảng Students, như được hiển thị bên dưới.

Required Attribute trong Entity Framework

Bây giờ, nếu bạn cố lưu thực thể Student mà không gán giá trị cho thuộc tính StudentName thì EF 6 sẽ ném ra ngoại lệ System.Data.Entity. Validation. DbEntityValidationException.

Lưu ý: Thuộc tính Required cũng được sử dụng trong ASP.NET MVC như một thuộc tính xác thực dữ liệu.

MaxLength Attribute trong Entity Framework

Thuộc tính MaxLength (MaxLength Attribute) có thể áp dụng cho một hoặc nhiều thuộc tính trong một lớp thực thể.

Nó chỉ định độ dài tối đa của giá trị dữ liệu được phép cho một thuộc tính và thiết lập kích thước của một cột tương ứng trong cơ sở dữ liệu.

Nó có thể áp dụng cho các thuộc tính kiểu string hoặc byte[] của một thực thể.


using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public int StudentID { get; set; }
    [MaxLength(50)]
    public string StudentName { get; set; }
        
}

Trong ví dụ trên, khai báo MaxLength(50) áp dụng trên thuộc tính StudentName chỉ định rằng giá trị của thuộc tính StudentName không thể dài hơn 50 ký tự.

Điều này sẽ tạo một cột StudentName có kích thước nvarchar(50) trong cơ sở dữ liệu SQL Server, như được hiển thị bên dưới.

MaxLength Attribute trong Entity Framework

Entity Framework cũng xác nhận giá trị của một thuộc tính MaxLength cho thuộc tính nếu bạn gán giá trị vượt kích thước đã chỉ định.

Ví dụ: nếu bạn gán giá trị chuỗi dài hơn 50 ký tự, thì EF 6 sẽ ném ra ngoại lệ System.Data.Entity.Validation. DbEntityValidationException.

Lưu ý: Thuộc tính MaxLength cũng được sử dụng trong ASP.NET MVC để xác thực giá trị của thuộc tính.

StringLength Attribute trong Entity Framework

Thuộc tính StringLength (StringLength Attribute) có thể áp dụng cho các thuộc tính kiểu string của một lớp thực thể.

Nó chỉ định số ký tự tối đa được phép cho thuộc tính chuỗi, và thiết lập kích thước của một cột tương ứng (kiểu nvarchar trong SQL Server) trong cơ sở dữ liệu.


using System.ComponentModel.DataAnnotations;

public class Student
{
    public int StudentID { get; set; }
    [StringLength(50)]
    public string StudentName { get; set; }
}

Như bạn có thể thấy trong đoạn mã trên, chúng tôi đã áp dụng thuộc tính StringLength cho một thuộc tính StudentName. Vì vậy, EF sẽ tạo cột StudentName có kiểu dữ liệu là nvarchar(50) trong cơ sở dữ liệu, như được hiển thị bên dưới.

StringLength Attribute trong Entity Framework

Entity Framework cũng xác nhận giá trị của một thuộc tính StringLength cho thuộc tính nếu bạn gán giá trị vượt kích thước đã chỉ định.

Ví dụ: nếu bạn đặt giá trị chuỗi thành hơn 50 ký tự, thì EF 6 sẽ ném ra ngoại lệ System.Data.Entity.Validation. DbEntityValidationException.

Lưu ý: Thuộc tính StringLength cũng có thể được sử dụng trong ASP.NET MVC để xác thực giá trị của thuộc tính.

Timestamp Attribute trong Entity Framework

Thuộc tính Timestamp (Timestamp Attribute) chỉ có thể áp dụng một lần trong một lớp thực thể cho thuộc tính kiểu mảng byte.

Nó tạo một cột với kiểu dữ liệu timestamp trong cơ sở dữ liệu SQL Server. EF API tự động sử dụng cột Timestamp này trong kiểm tra xung đột trên câu lệnh UPDATE trong cơ sở dữ liệu.


using System.ComponentModel.DataAnnotations;

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
        
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

Trong ví dụ trên, thuộc tính Timestamp áp dụng cho thuộc tính RowVersion kiểu byte[] của thực thể Student.

Vì vậy, EF sẽ tạo một cột có tên RowVersion với kiểu dữ liệu timestamp trong bảng Students trong cơ sở dữ liệu SQL Server, như được hiển thị bên dưới.

Timestamp Attribute trong Entity Framework

Cột RowVersion sẽ được thêm trong mệnh đề where bất cứ khi nào bạn cập nhật một thực thể và gọi phương thức SaveChanges.


using(var context = new SchoolContext()) 
{
    var std = new Student()
    {
        StudentName = "Bill"
    };

    context.Students.Add(std);
    context.SaveChanges();

    std.StudentName = "Steve";
    context.SaveChanges();
}

Đoạn mã trên sẽ thực thi câu lệnh UPDATE sau trong cơ sở dữ liệu.

exec sp_executesql N'UPDATE [dbo].[Students]
SET [StudentName] = @0
WHERE (([StudentId] = @1) AND ([RowVersion] = @2))
SELECT [RowVersion]
FROM [dbo].[Students]
WHERE @@ROWCOUNT > 0 AND [StudentId] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8)',@0=N'Steve',@1=1,@2=0x00000000000007D1
go

DatabaseGenerated Attribute trong Entity Framework

Như bạn đã biết, theo mặc định EF tạo một cột IDENTITY trong cơ sở dữ liệu cho tất cả các thuộc tính id (khóa) của thực thể.

Vì vậy, cơ sở dữ liệu sẽ tạo ra một giá trị cho cột này trên mỗi lệnh INSERT. Ví dụ: SQL Server tạo cột IDENTITY số nguyên với identity là 1 và tăng thêm 1 mỗi lần INSERT.

EF 6 cung cấp thuộc tính chú thích dữ liệu được tạo ra cho cơ sở dữ liệu để cấu hình cách tạo ra giá trị của một thuộc tính. Thuộc tính DatabaseGenerated lấy một trong ba giá trị enum của DatabaseGeneratedOption sau đây:

  1. DatabaseGeneratedOption.None
  2. DatabaseGeneratedOption.Identity
  3. DatabaseGeneratedOption.Computing

DatabaseGeneratedOption . None

Tùy chọn DatabaseGeneratedOption.None chỉ định rằng giá trị của thuộc tính sẽ không được tạo bởi cơ sở dữ liệu. Điều này sẽ hữu ích để ghi đè quy ước mặc định cho các thuộc tính id.

Ví dụ: nếu bạn muốn cung cấp các giá trị của riêng mình cho các thuộc tính id thay vì các giá trị được tạo bởi cơ sở dữ liệu, hãy sử dụng tùy chọn None, như được trình bày bên dưới.


public class Course
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CourseId { get; set; }
    public string CourseName { get; set; }
}

Trong ví dụ trên, EF sẽ tạo cột CourseId trong cơ sở dữ liệu và sẽ không đánh dấu nó là cột IDENTITY. Vì vậy, mỗi lần bạn sẽ phải cung cấp giá trị của thuộc tính CourseId trước khi gọi phương thức SaveChanges.


using (var context = new SchoolContext())
{
    // you must provide the unique CourseId value
    var maths = new Course(){ CourseId=1,  CourseName="Maths"};
    context.Courses.Add(maths);

    // you must provide the unique CourseId value
    var eng = new Course(){ CourseId=2,  CourseName="English"};
    context.Courses.Add(eng);

    // the following will throw an exception as CourseId has duplicate value
    //var sci = new Course(){ CourseId=2,  CourseName="sci"};

    context.SaveChanges();
}
Lưu ý: EF sẽ đưa ra một ngoại lệ nếu bạn không cung cấp các giá trị duy nhất vì CourseId là thuộc tính khóa chính.

DatabaseGeneratedOption . Identity

Bạn có thể đánh dấu các thuộc tính không phải khóa (không phải id) là thuộc tính do DB tạo giá trị bằng cách sử dụng tùy chọn DatabaseGeneratedOption.Identity.

Điều này xác định rằng giá trị của thuộc tính sẽ được tạo bởi cơ sở dữ liệu trên câu lệnh INSERT. Thuộc tính Identity này không thể được cập nhật.

Xin lưu ý rằng cách giá trị của thuộc tính Identity sẽ được tạo bởi cơ sở dữ liệu tùy thuộc vào nhà cung cấp cơ sở dữ liệu. Nó có thể là identity, rowversion hoặc GUID. SQL Server tạo một cột identity cho một thuộc tính kiểu số nguyên.


public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int RecordNum { get; set; }
}

Trong ví dụ trên, thuộc tính RecordNum sẽ là một thuộc tính identity. Điều này có nghĩa là EF sẽ tạo cột IDENTITY trong cơ sở dữ liệu SQL Server cho thuộc tính này.

DatabaseGeneratedOption . Compute

Tùy chọn DatabaseGeneratedOption.Compute chỉ định rằng giá trị của thuộc tính sẽ được tạo bởi cơ sở dữ liệu khi INSERT và sau đó, trên mỗi bản cập nhật tiếp theo.

Giống như Identity, cách cơ sở dữ liệu tạo ra giá trị phụ thuộc vào nhà cung cấp cơ sở dữ liệu. Bạn có thể cấu hình giá trị mặc định hoặc sử dụng một trigger cho cột được tính toán này.

Hãy xem xét ví dụ sau.


public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreatedDate { get; set; }
} 

Trong ví dụ trên, thuộc tính CreatedDate được đánh dấu bằng tùy chọn DatabaseGeneratedOption.Computed. Điều này cho EF biết rằng các giá trị được tạo cho cột này trong cơ sở dữ liệu.

Tuy nhiên, EF không đảm bảo rằng nó sẽ thiết lập cơ chế thực tế để tạo ra các giá trị.

Ở đây, chúng tôi sẽ chỉ định chức năng ngày của SQL Server sẽ tạo giá trị ngày giờ hiện tại trên lệnh INSERT, như được hiển thị bên dưới.


protected override void OnModelCreating(ModelBuilder modelBuilder)
{            
    modelBuilder.Entity<Student>()
            .Property(s => s.CreatedDate)
            .HasDefaultValueSql("GETDATE()");
}

Đoạn mã trên gán giá trị của hàm GETDATE() của SQL Server làm giá trị mặc định SQL sẽ chèn ngày và giờ hiện tại trên mỗi lệnh INSERT.

Lưu ý: EF không có các cột DatabaseGeneratedOption.Computed trong các câu lệnh INSERT hoặc UPDATE.

ConcurrencyCheck Attribute trong Entity Framework

Thuộc tính ConcurrencyCheck (ConcurrencyCheck Attribute) có thể áp dụng cho một hoặc nhiều thuộc tính trong một lớp thực thể trong EF 6.

Khi áp dụng cho một thuộc tính, cột tương ứng trong bảng cơ sở dữ liệu sẽ được sử dụng trong kiểm tra xung đột bằng cách sử dụng mệnh đề where.


using System.ComponentModel.DataAnnotations;

public class Student
{
    public int StudentId { get; set; }
     
    [ConcurrencyCheck]
    public string StudentName { get; set; }
}

Trong ví dụ trên, thuộc tính ConcurrencyCheck áp dụng cho thuộc tính StudentName của lớp thực thể Student. Vì vậy, EF sẽ bao gồm cột StudentName trong câu lệnh UPDATE để kiểm tra sự xung đột. Hãy xem xét ví dụ sau.


using(var context = new SchoolContext()) 
{
    var std = new Student()
    {
        StudentName = "Bill"
    };

    context.Students.Add(std);
    context.SaveChanges();

    std.StudentName = "Steve";
    context.SaveChanges();
}

Ví dụ trên sẽ thực thi câu lệnh UPDATE sau khi gọi phương thức SaveChanges(), trong đó nó có StudentName trong mệnh đề where.


exec sp_executesql N'UPDATE [dbo].[Students]
SET [StudentName] = @0
WHERE (([StudentId] = @1) AND ([StudentName] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Steve',@1=1,@2=N'Bill'
go
Lưu ý: Các thuộc tính Timestamp chỉ có thể áp dụng cho duy nhất một thuộc tính kiểu mảng byte, trong khi các thuộc tính ConcurrencyCheck có thể áp dụng cho bất kỳ số lượng các thuộc tính với bất kỳ kiểu dữ liệu nào.


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.