Entity Framework Fluent API được sử dụng để cấu hình các lớp thực thể để ghi đè các quy ước mặc định của Entity Framework. Fluent API dựa trên mẫu thiết kế Fluent API (hay còn gọi là giao diện thông thạo) trong đó kết quả được tạo thành từ một chuỗi phương thức.
Trong Entity Framework 6, lớp DbModelBuilder hoạt động như một Fluent API, chúng ta có thể sử dụng nó để thực hiện các cấu hình nhiều thứ khác nhau. Nó cung cấp nhiều tùy chọn cấu hình hơn các attribute chú thích dữ liệu.
Để viết các cấu hình Fluent API, chúng ta cần ghi đè phương thức OnModelCreating()
của lớp DbContext
trong một lớp Context tùy chỉnh, như được trình bày bên dưới.
public class SchoolContext: DbContext
{
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Write Fluent API configurations here
}
}
Bạn có thể sử dụng các attribute chú thích dữ liệu và Fluent API cùng một lúc. Entity Framework ưu tiên Fluent API hơn các attribute chú thích dữ liệu.
Fluent API cấu hình các khía cạnh sau của một mô hình trong Entity Framework 6:
Bảng sau liệt kê các phương thức quan trọng của Fluent API:
Phương thức | Mô tả |
---|---|
Cấu hình toàn mô hình | |
HasDefaultSchema | Chỉ định lược đồ cơ sở dữ liệu mặc định. |
ComplexType | Cấu hình lớp là kiểu phức tạp. |
Cấu hình thực thể | |
HasIndex | Cấu hình thuộc tính Index cho kiểu thực thể. |
HasKey | Cấu hình thuộc tính khóa chính cho kiểu thực thể. |
HasMany | Cấu hình mối quan hệ một-nhiều hoặc nhiều-nhiều. |
HasOptional | Cấu hình một mối quan hệ tùy chọn sẽ tạo khóa ngoại không thể hủy trong cơ sở dữ liệu. |
HasRequired | Cấu hình mối quan hệ bắt buộc sẽ tạo cột khóa ngoại không thể rỗng trong cơ sở dữ liệu. |
Ignore | Cấu hình lớp hoặc thuộc tính không được ánh xạ vào bảng hoặc cột trong cơ sở dữ liệu. |
Map | Cho phép cấu hình nâng cao liên quan đến cách thực thể được ánh xạ tới lược đồ cơ sở dữ liệu. |
MapToStoredProcedures | Cấu hình kiểu thực thể để sử dụng các stored procedure INSERT, UPDATE và DELETE. |
ToTable | Cấu hình tên bảng cho thực thể. |
Cấu hình thuộc tính | |
HasColumnAnnotation | Đặt một chú thích trong mô hình cho cột cơ sở dữ liệu được sử dụng để lưu trữ thuộc tính. |
IsRequired | Cấu hình thuộc tính bắt buộc nhập dữ liệu khi gọi phương thức SaveChanges. |
IsConcurrencyToken | Cấu hình thuộc tính được sử dụng làm mã thông báo Concurrency. |
IsOptional | Cấu hình thuộc tính là tùy chọn sẽ tạo một cột nullable trong cơ sở dữ liệu. |
HasParameterName | Cấu hình tên của tham số được sử dụng trong stored procedure cho thuộc tính. |
HasDatabaseGeneratedOption | Cấu hình cách tạo giá trị cho cột tương ứng trong cơ sở dữ liệu, ví dụ tính toán, danh tính hoặc không có. |
HasColumnOrder | Cấu hình thứ tự của cột trong cơ sở dữ liệu được sử dụng để lưu trữ thuộc tính. |
HasColumnType | Cấu hình kiểu dữ liệu của cột tương ứng của một thuộc tính trong cơ sở dữ liệu. |
HasColumnName | Cấu hình tên cột tương ứng của một thuộc tính trong cơ sở dữ liệu. |
IsConcurrencyToken | Cấu hình thuộc tính được sử dụng làm mã thông báo Concurrency. |
Fluent API có thể được sử dụng để định cấu hình một thực thể để ánh xạ nó với bảng cơ sở dữ liệu, lược đồ mặc định, v.v.
Đầu tiên, hãy cấu hình một lược đồ mặc định cho các bảng trong cơ sở dữ liệu. Tuy nhiên, bạn có thể thay đổi lược đồ trong khi tạo các bảng riêng lẻ.
Ví dụ sau đặt lược đồ Admin làm lược đồ mặc định. Tất cả các đối tượng cơ sở dữ liệu sẽ được tạo trong lược đồ Quản trị trừ khi bạn chỉ định rõ ràng một lược đồ khác.
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 default schema
modelBuilder.HasDefaultSchema("Admin");
}
}
Code First sẽ tạo các bảng cơ sở dữ liệu với tên của các thuộc tính DbSet
trong lớp Context, trong trường hợp này là Students
và Standards
.
Bạn có thể ghi đè quy ước này và đặt tên bảng khác với các thuộc tính DbSet
, như ví dụ ở bên dưới.
namespace CodeFirst_FluentAPI_Tutorials
{
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 default schema
modelBuilder.HasDefaultSchema("Admin");
//Map entity to table
modelBuilder.Entity<Student>().ToTable("StudentInfo");
modelBuilder.Entity<Standard>().ToTable("StandardInfo","dbo");
}
}
}
Như bạn có thể thấy trong ví dụ trên, chúng ta bắt đầu với phương thức Entity<TEntity>()
. Hầu như bạn sẽ phải bắt đầu với phương thức Entity<TEntity>()
để định cấu hình bằng Fluent API.
Chúng tôi đã sử dụng phương thức ToTable()
để ánh xạ thực thể Student
vào bảng StudentInfo
và thực thể Standard
vào bảng StandardInfo
.
Lưu ý rằng bảng StudentInfo
nằm trong lược đồ Admin và bảng StandardInfo
nằm trong lược đồ dbo vì chúng tôi đã chỉ định lượng đồ mặc định là Admin và chỉ định lược đồ dbo cho bảng StandardInfo
.
Ví dụ sau đây minh họa cách ánh xạ thực thể Student
vào nhiều bảng trong cơ sở dữ liệu.
namespace CodeFirst_FluentAPI_Tutorials
{
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)
{
modelBuilder.Entity<Student>().Map(m =>
{
m.Properties(p => new
{
p.StudentId,
p.StudentName
});
m.ToTable("StudentInfo");
}).Map(m =>
{
m.Properties(p => new
{
p.StudentId,
p.Height,
p.Weight,
p.Photo,
p.DateOfBirth
});
m.ToTable("StudentInfoDetail");
});
modelBuilder.Entity<Standard>().ToTable("StandardInfo");
}
}
}
Như bạn có thể thấy trong ví dụ trên, chúng tôi đã ánh xạ một số thuộc tính của thực thể Student
vào bảng StudentInfo
và các thuộc tính khác vào bảng StudentInfoDetail
bằng phương thức Map()
.
Do đó, thực thể Student
sẽ chia thành hai bảng, như hình dưới đây.
Phương thức Map()
yêu cầu một tham số kiểu delegate. Bạn có thể truyền một delegate Action hoặc biểu thức lambda trong phương thức Map()
, như ví dụ bên dưới.
using System.Data.Entity.ModelConfiguration.Configuration;
namespace CodeFirst_FluentAPI_Tutorials
{
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)
{
modelBuilder.Entity<Student>().Map(delegate(EntityMappingConfiguration<Student> studentConfig)
{
studentConfig.Properties(p => new
{
p.StudentId,
p.StudentName
});
studentConfig.ToTable("StudentInfo");
});
Action<EntityMappingConfiguration<Student>> studentMapping = m =>
{
m.Properties(p => new
{
p.StudentId,
p.Height,
p.Weight,
p.Photo,
p.DateOfBirth
});
m.ToTable("StudentInfoDetail");
};
modelBuilder.Entity<Student>().Map(studentMapping);
modelBuilder.Entity<Standard>().ToTable("StandardInfo");
}
}
}
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á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
});
}
}
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()
và 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.
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();
}
}
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.
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.
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
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.
Entity Framework Core toàn tập sẽ hướng dẫn bạn tất cả mọi thứ về Entity Framework Core.