EF Code-First - Ánh xạ thuộc tính

Ánh xạ thuộc tính bằng Fluent API

Fluent API có thể được sử dụng để cấu hình các thuộc tính của thực thể để ánh xạ nó với cột db.

Sử dụng Fluent API, bạn có thể thay đổi tên cột, kiểu dữ liệu, kích thước, Null hoặc NotNull, PrimaryKey, ForeignKey, cột concurrency, v.v.

Chúng tôi sẽ cấu hình các lớp thực thể sau.

public class Student
{
    public int StudentKey { 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 Standard Standard { get; set; }
}
    
public class Standard
{
    public int StandardKey { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}

Cấu hình khóa chính và khóa chính tổng hợp

Các lớp thực thể của chúng tôi ở trên, không tuân theo quy ước Code First cho khóa chính vì chúng không có thuộc tính Id hoặc {Tên lớp} + "Id".

Vì vậy, bạn có thể cấu hình thuộc tính khóa bằng phương thức HasKey() như dưới đây. Hãy nhớ rằng modelBuilder.Entity<TEntity>() trả về đối tượng EntityTypeConfiguration.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure primary key
        modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);
        modelBuilder.Entity<Standard>().HasKey<int>(s => s.StandardKey);

        //Configure composite primary key
        modelBuilder.Entity<Student>().HasKey<int>(s => new 
        { 
            s.StudentKey, 
            s.StudentName 
        }); 
    }
}

Cấu hình tên cột, kiểu dữ liệu và thứ tự

Quy ước Code First mặc định tạo một cột cho một thuộc tính có cùng tên, thứ tự và kiểu dữ liệu. Bạn có thể ghi đè quy ước này, như ví dụ bên dưới.


public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure Column
        modelBuilder.Entity<Student>()
                    .Property(p => p.DateOfBirth)
                    .HasColumnName("DoB")
                    .HasColumnOrder(3)
                    .HasColumnType("datetime2");
    }
}

Như bạn có thể thấy trong ví dụ trên, phương thức Property() được sử dụng để cấu hình một thuộc tính của một thực thể.

Phương thức HasColumnName() được sử dụng để thay đổi tên cột của thuộc tính DateOfBirth. Ngoài ra, các phương thức HasColumnOrder()HasColumnType() thay đổi thứ tự và kiểu dữ liệu của cột tương ứng.

Phương thức modelBuilder.Entity<TEntity>() .Property(expression) cho phép bạn sử dụng các phương thức khác nhau để định cấu hình một thuộc tính cụ thể, như hình ảnh bên dưới.

configure property with fluent api Entity Framework code-first


Cấu hình cột Null hoặc NotNull

EF 6 API sẽ tạo cột NotNull cho thuộc tính kiểu dữ liệu nguyên thủy vì kiểu dữ liệu nguyên thủy không thể Null trừ khi được đánh dấu là nullable bằng cách sử dụng dấu ? hoặc kiểu Nullable<T>.

Sử dụng phương thức IsOptional() để tạo một cột nullable cho một thuộc tính. Theo cách tương tự, sử dụng phương thức IsRequired() để tạo cột NotNull.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //Configure Null Column
        modelBuilder.Entity<Student>()
                .Property(p => p.Heigth)
                .IsOptional();
                        
            //Configure NotNull Column
            modelBuilder.Entity<Student>()
                .Property(p => p.Weight)
                .IsRequired();
    }
}

Cấu hình kích thước cột

Code First sẽ đặt kích thước tối đa của kiểu dữ liệu cho một cột. Bạn có thể ghi đè quy ước này, như ví dụ bên dưới.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName column size to 50
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50);
                        
        //Set StudentName column size to 50 and change datatype to nchar 
        //IsFixedLength() change datatype from nvarchar to nchar
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50).IsFixedLength();
                        
        //Set size decimal(2,2)
            modelBuilder.Entity<Student>()
                .Property(p => p.Height)
                .HasPrecision(2, 2);
    }
}

Như bạn có thể thấy trong ví dụ trên, chúng tôi đã sử dụng phương thức HasMaxLength() để thiết lập kích thước của một cột.

Phương thức IsFixedLength() chuyển kiểu nvarchar thành kiểu nchar. Theo cách tương tự, phương thức HasPrecision() cũng thay đổi độ chính xác của cột decimal.

Cấu hình cột concurrency

Bạn có thể cấu hình một thuộc tính dưới dạng cột concurrency (chống xung đột) bằng phương thức ConcurrencyToken(), như được trình bày bên dưới.

public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName as concurrency column
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .IsConcurrencyToken();
    }
}

Như bạn đã thấy ở trên, chúng tôi thiết lập cột StudentName là cột concurrency để nó sẽ được thêm trong mệnh đề where trong các lệnh UPDATE và DELETE.

Bạn cũng có thể sử dụng phương thức IsRowVersion() cho thuộc tính kiểu byte[] để biến nó thành một cột concurrency.