EF Code-First - Thuộc tính DatabaseGenerated

Thuộc tính DatabaseGenerated 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.