EF CodeFirst系列(4)---FluentApi


FluentApi總結

1.FluentApi簡介

  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方法及其作用:

配置 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() 配置數據庫中對應列用於樂觀並發檢測

2.實體相關配置

1.實體簡單配置

直接上栗子:

我們新建一個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)

2.實體映射到多張表

有時候我們希望一個實體的屬性分在兩種表中,那么該怎么配置呢?還用上邊的栗子,我們把學生的姓名和Id存在一張表,學號和Id放在另一張表中,代碼如下:

    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函數,生成了新的數據庫,如下所示:

我們看到,通過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");
        }
    }

 3.屬性相關配置

屬性的配置比較簡單,這里簡單總結了主鍵,列基本屬性,是否可空,數據長度,高並發的配置。

一個栗子:

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上判斷是否並發              
        }
    }

執行程序后生成的數據庫如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM