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 = , 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的更多相关文章
- EF CodeFirst系列(3)---EF中的继承策略(暂存)
我们初始化数据库一节已经知道:EF为每一个具体的类生成了数据库的表.现在有了一个问题:我们在设计领域类时经常用到继承,这能让我们的代码更简洁且容易管理,在面向对象中有“has a”和“is a”关系 ...
- EF CodeFirst系列(6)---配置1对1,1对多,多对多关系
这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下. 1. 1对0/1关系配置 1. 通 ...
- EF CodeFirst系列(7)---FluentApi配置存储过程
FluentApi配置存储过程 1.EF自动生成存储过程 EF6的CodeFirst开发模式支持给实体的CUD操作配置存储过程,当我们执行SaveChanges()方法时EF不在生成INSERT,UP ...
- EF CodeFirst系列(8)--- FluentApi配置单个实体
我们已经知道了在OnModelCreating()方法中可以通过FluentApi对所有的实体类进行配置,然而当实体类很多时,我们把所有的配置都放在OnModelCreating()方法中很难维护.E ...
- 2.简单的Code First例子(EF Code-First系列)
现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...
- 3.Code-First 约定(EF Code-First系列)
前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...
- 6.Configure Domain Classes(配置领域类)【EF Code-First 系列】
在前面的部分中,我们学习了Code-First默认约定,Code-First使用默认的约定,根据你的领域类,然后生成概念模型. Code-First模式,发起了一种编程模式:约定大于配置.这也就是说, ...
- EF CodeFirst系列(1)---CodeFirst简单入门
1.什么是CodeFirst 从EF4.1开始,EF可以支持CodeFirst开发模式,这种开发模式特别适用于领域驱动设计(Domain Driven Design,大名鼎鼎的DDD).在CodeFi ...
- EF CodeFirst系列(2)---CodeFirst的数据库初始化
1. CodeFirst的默认约定 1.领域类和数据库架构的映射约定 在介绍数据库的初始化之前我们需要先了解领域类和数据库之间映射的一些约定.在CodeFirst模式中,约定指的是根据领域类(如Stu ...
随机推荐
- 【PAT】A1002 A+B for Polynomials
仅有两个要注意的点: 如果系数为0,则不输出,所以输入结束以后要先遍历确定系数不为零的项的个数 题目最后一句,精确到小数点后一位,如果这里忽略了,会导致样例1,3,4,5都不能通过
- docker-compose编排项目redis容器实现主从复制
一.pip管理工具安装 docker-compose是python项目,所以安装需要通过python下的包管理工具pip安装.一般linux服务器都会预安装有python环境,所以优先检查python ...
- LeetCode算法题-Reverse String II(Java实现)
这是悦乐书的第256次更新,第269篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第123题(顺位题号是541).给定一个字符串和一个整数k,你需要反转从字符串开头算起的 ...
- 单元测试(qunit)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- [已决解]关于Hadoop start-all.sh启动问题
问题一:出现Attempting to operate on hdfs namenode as root 写在最前注意: 1.master,slave都需要修改start-dfs.sh,stop-df ...
- 基于element ui的级联选择器组件实现的分类后台接口
今天在做资产管理系统的时候遇到一个分类的级联选择器,前端是用的element的组件,需要后台提供接口支持. 这个组件需要传入的数据结构大概是这样的,详细的可参考官方案例: [{ value: ...
- Re:Exgcd解二元不定方程
模拟又炸了,我死亡 $exgcd$(扩展欧几里德算法)用于求$ax+by=gcd(a,b)$中$x,y$的一组解,它有很多应用,比如解二元不定方程.求逆元等等,这里详细讲解一下$exgcd$的原理. ...
- tiff图片拆分
本程序下载地址: tiff格式的图片可以由多张图片合成, 也可以拆分为多张图片.不管是合成或者拆分,都借助了第三方开源库Cximage,对于这个图像库的使用,我们没有必要去一行一行的去看它的代码实现, ...
- Numpy基本操作
NumPy:数组计算 NumPy是高性能科学计算和数据分析的基础包.它是Pandas等其他各种工具的基础 NumPy的主要功能: ndarray,一个多维数据结构,高校且节省空间 无需循环即可对整组数 ...
- 安装Java和Tomcat
安装Java 下载java源码包 安装的是JDK8,下载地址如下:下载链接 注意,不要在服务器中使用wget来下载jdk,因为oracle会认为你是爬虫,下载的文件不是jdk,而是一个html文件. ...