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 = , 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
.IsOptional(); //可以为null //设置姓名
modelBuilder.Entity<Student>().Property(s => s.StudentName)
.HasMaxLength() //最长20
.IsRequired() //不能为null
.IsConcurrencyToken(); //用于乐观并发检测,delete或者update时,这个属性添加到where上判断是否并发
}
}

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

EF CodeFirst系列(5)---FluentApi的更多相关文章

  1. EF CodeFirst系列(3)---EF中的继承策略(暂存)

    我们初始化数据库一节已经知道:EF为每一个具体的类生成了数据库的表.现在有了一个问题:我们在设计领域类时经常用到继承,这能让我们的代码更简洁且容易管理,在面向对象中有“has  a”和“is a”关系 ...

  2. EF CodeFirst系列(6)---配置1对1,1对多,多对多关系

    这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下. 1. 1对0/1关系配置 1. 通 ...

  3. EF CodeFirst系列(7)---FluentApi配置存储过程

    FluentApi配置存储过程 1.EF自动生成存储过程 EF6的CodeFirst开发模式支持给实体的CUD操作配置存储过程,当我们执行SaveChanges()方法时EF不在生成INSERT,UP ...

  4. EF CodeFirst系列(8)--- FluentApi配置单个实体

    我们已经知道了在OnModelCreating()方法中可以通过FluentApi对所有的实体类进行配置,然而当实体类很多时,我们把所有的配置都放在OnModelCreating()方法中很难维护.E ...

  5. 2.简单的Code First例子(EF Code-First系列)

    现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...

  6. 3.Code-First 约定(EF Code-First系列)

    前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...

  7. 6.Configure Domain Classes(配置领域类)【EF Code-First 系列】

    在前面的部分中,我们学习了Code-First默认约定,Code-First使用默认的约定,根据你的领域类,然后生成概念模型. Code-First模式,发起了一种编程模式:约定大于配置.这也就是说, ...

  8. EF CodeFirst系列(1)---CodeFirst简单入门

    1.什么是CodeFirst 从EF4.1开始,EF可以支持CodeFirst开发模式,这种开发模式特别适用于领域驱动设计(Domain Driven Design,大名鼎鼎的DDD).在CodeFi ...

  9. EF CodeFirst系列(2)---CodeFirst的数据库初始化

    1. CodeFirst的默认约定 1.领域类和数据库架构的映射约定 在介绍数据库的初始化之前我们需要先了解领域类和数据库之间映射的一些约定.在CodeFirst模式中,约定指的是根据领域类(如Stu ...

随机推荐

  1. [spring boot] Table 'yhm.hibernate_sequence' doesn't exist

    在使用该注解时:@GeneratedValue要注意的几点: @GeneratedValue注解的strategy属性提供四种值: -AUTO主键由程序控制, 是默认选项 ,不设置就是这个 -IDEN ...

  2. python3 多线程的使用

    示例1: import threadingfrom time import sleep class forThread(threading.Thread): def __init__(self, ev ...

  3. Nginx 配置 https

    从云服务提供商处申请证书 申请 https 证书教程-百度经验 申请下来的证书目录结构 . ├── Apache │   ├── 1_root_bundle.crt │   ├── 2_website ...

  4. 通过指令码来判断Java代码的执行顺序(++问题与return和finally的问题)

    问题 在<深入理解Java虚拟机>一书中遇到了如下代码: public int method() { int i; try { i = 1; return i; } catch (Exce ...

  5. .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]

    原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...

  6. Python开发【内置模块篇】configparser

    生成配置文件 import configparser config = configparser.ConfigParser() config[', 'Compression': 'yes', ', ' ...

  7. os模块使用

    Python获取当前文件名的两种方法 1,使用python文件默认的‘ file ’属性 2,使用 sys.argv[0] print sys.argv # 输入参数列表print sys.argv[ ...

  8. Linux下添加windows字体

    在Linux下使用wqy字体,在视觉效果上就已近很好了,其实没有必要添加windows字体.但是显然有些人(比如领导,^..^)就喜欢宋体.楷体,所以添加windows字体有时还是需要的,幸运的是这件 ...

  9. ubuntu添加普通用户,并解决远程登录

    创建普通用户 # 创建用户,并指定用户目录,加入用户组sudo useradd username -d /home/username -m #设置密码 sudo passwd username #给用 ...

  10. Oracle 执行计划(三)-------表连接方式

    SQL FOR TESTING: create table qcb_student_test( student_id number, student_name varchar2(20), studen ...