EF CodeFirst系列(5)---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上判断是否并发              
        }
    }
复制代码

执行程序后生成的数据库如下:

转载于:https://www.cnblogs.com/jhxk/articles/10437306.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值