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方法及其做用: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() 配置數據庫中對應列用於樂觀併發檢測

2.實體相關配置

1.實體簡單配置

直接上栗子: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

2.實體映射到多張表

有時候咱們但願一個實體的屬性分在兩種表中,那麼該怎麼配置呢?還用上邊的栗子,咱們把學生的姓名和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");
        }
    }

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

執行程序後生成的數據庫以下:

相關文章
相關標籤/搜索