EF中的FluentApi做用是經過配置領域類來覆蓋默認的約定。在EF中,咱們經過DbModelBuilder類來使用FluentApi,它的功能比數據註釋屬性更強大。數據庫
使用FluentApi時,咱們在context類的OnModelCreating()方法中重寫配置項,一個栗子:架構
public class SchoolContext: DbContext { public DbSet<Student> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Write Fluent API configurations here } }
咱們能夠把FluentApi和數據註釋屬性一塊兒使用,當FluentApi和數據註釋屬性都配置了同一個項時,採用FluentApi中的配置。併發
在EF6中FluentApi能夠配置領域類的如下幾個方面,下表也列出了一些經常使用的FluentApi方法及其做用:app
配置 | Fluent API 方法 | 做用 |
---|---|---|
架構相關配置 | HasDefaultSchema() | 數據庫的默認架構 |
ComplexType() | 把一個類配置爲複雜類型 | |
實體相關配置 | HasIndex() | 實體的的索引 |
HasKey() | 實體的主鍵(可其實現複合主鍵,[Key]在EF core中不能實現複合主鍵) | |
HasMany() | 1對多的或者 多對多關係 | |
HasOptional() | 一個可選的關係,這樣配置會在數據庫中生成一個可空的外鍵 | |
HasRequired() | 一個必有的關係,這樣配置會在數據庫中生成一個不能爲空的外鍵 | |
Ignore() | 實體或者實體的屬性不映射到數據庫 | |
Map() | 設置一些優先的配置 | |
MapToStoredProcedures() | 實體的CUD操做使用存儲過程 | |
ToTable() | 爲實體設置表名 | |
屬性相關配置 | HasColumnAnnotation() | 給屬性設置註釋 |
IsRequired() | 在調用SaveChanges()方法時,屬性不能爲空 | |
IsOptional() | 可選的,在數據庫生成可空的列 | |
HasParameterName() | 配置用於該屬性的存儲過程的參數名 | |
HasDatabaseGeneratedOption() | 配置數據庫中對應列的值怎樣生成的,如計算,自增等 | |
HasColumnOrder() | 配置數據庫中對應列的排列順序 | |
HasColumnType() | 配置數據庫中對應列的數據類型 | |
HasColumnName() | 配置數據庫中對應列的列名 | |
IsConcurrencyToken() | 配置數據庫中對應列用於樂觀併發檢測 |
直接上栗子:ide
咱們新建一個EF6Demo的控制檯應用程序,添加Student和Grade實體,以及上下文類SchoolContext,代碼以下:函數
//學生類 public class Student { public int StudentId { get; set; } public string StudentName { get; set; } public string StudentNo { get; set; } public virtual Grade Grade{get;set;} } //年級類 public class Grade { public int GradeId { get; set; } public string GradeName { get; set; } public virtual ICollection<Student> Students { get; set; } } //上下文類 public class SchoolContext:DbContext { public SchoolContext() : base() { } public DbSet<Student> Students { get; set; } public DbSet <Grade> Grades { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("Admin");//添加默認架構名 modelBuilder.Entity<Student>().ToTable("StudentInfo"); modelBuilder.Entity<Grade>().ToTable("GradeInfo","NewAdmin");//設置表名和架構 } }
在Main函數中執行代碼:高併發
class Program { static void Main(string[] args) { using (SchoolContext context=new SchoolContext()) { context.Students.Add(new Student() { StudentId = 1, StudentName = "Jack" }); context.SaveChanges(); } } }
這時在內置的SqlServer中生成數據庫,以下圖所示,咱們看到Student表名爲StudentInfo,架構是Admin;Grade表名是GradeInfo,架構是NewAdmin,覆蓋了默認的約定(默認表名爲dbo.Students和dbo.Grades)ui
有時候咱們但願一個實體的屬性分在兩種表中,那麼該怎麼配置呢?還用上邊的栗子,咱們把學生的姓名和Id存在一張表,學號和Id放在另外一張表中,代碼以下:spa
public class SchoolContext:DbContext { public SchoolContext() : base() { } public DbSet<Student> Students { get; set; } public DbSet <Grade> Grades { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Student>().Map(m => { //配置第一張表,包含學生Id和學生姓名 m.Properties(p => new { p.StudentId, p.StudentName }); m.ToTable("StudentInfo"); }).Map(m => { //配置第二張表,包含學生Id和學生學號 m.Properties(p => new { p.StudentId, p.StudentNo }); m.ToTable("StudentInfo2"); }); //配置年級表名 modelBuilder.Entity<Grade>().ToTable("GradeInfo"); } }
運行一下Main函數,生成了新的數據庫,以下所示:code
咱們看到,經過Map()方法,咱們把Student實體的屬性被分在了兩個表中。modelBuilder.Entity<T>()方法返回的是一個EntityTypeConfiguration<T>類型,Map()方法的參數是一個委託類型,委託的輸入參數是EntityMappingConfiguration的實例。咱們能夠自定義一個委託來實現配置,下邊的代碼運行後生成的數據庫和和上邊同樣:
public class SchoolContext : DbContext { public SchoolContext() : base() { } public DbSet<Student> Students { get; set; } public DbSet<Grade> Grades { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //先定義一個Action委託備用,委託的輸入參數是一個實體映射配置(EntityMappingConfiguration)的實例 Action<EntityMappingConfiguration<Student>> studentMapping = m => { m.Properties(p => new { p.StudentId, p.StudentNo }); m.ToTable("StudentInfo2"); }; modelBuilder.Entity<Student>() //第一張表Map()方法參數是delegate形式委託 .Map(delegate (EntityMappingConfiguration<Student> studentConfig) { //map參數是lambda表達式 studentConfig.Properties(p => new { p.StudentId, p.StudentName }); studentConfig.ToTable("StudentInfo"); }) //第二張表Map()方法參數是Action委託 .Map(studentMapping); modelBuilder.Entity<Grade>().ToTable("GradeInfo"); } }
屬性的配置比較簡單,這裏簡單總結了主鍵,列基本屬性,是否可空,數據長度,高併發的配置。
一個栗子:
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 Grade Grade{ get; set; }//年級 } public class Grade { public int GradeKey { get; set; }//主鍵 public string GradeName { get; set; }//年級名 public ICollection<Student> Students { get; set; } }
使用FluentApi對領域類作了如下配置:
public class SchoolContext : DbContext { public SchoolContext() : base() { } public DbSet<Student> Students { get; set; } public DbSet<Grade> Grades { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //設置默認架構 modelBuilder.HasDefaultSchema("Admin"); //設置主鍵 modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey); //設置不映射的屬性 modelBuilder.Entity<Student>().Ignore(s => s.Height); //設置DateOfBirth modelBuilder.Entity<Student>().Property(p => p.DateOfBirth) .HasColumnName("birthday") //列名爲birthday .HasColumnType("datetime2") //數據類型是datetime類型 .HasColumnOrder(3) //順序編號是3 .IsOptional(); //能夠爲null //設置姓名 modelBuilder.Entity<Student>().Property(s => s.StudentName) .HasMaxLength(20) //最長20 .IsRequired() //不能爲null .IsConcurrencyToken(); //用於樂觀併發檢測,delete或者update時,這個屬性添加到where上判斷是否併發 } }
執行程序後生成的數據庫以下: