Fluent API配置:

前面我们已经了解到使用DataAnotations特性来覆写Code-First默认约定,现在我们来学习Fluent API。

Fluent API是另一种配置领域类的方法,它比DataAnnotations特性提供更多的配置方法,下表是Fluent API支持的类型映射。

映射种类 配置数据库
模型(Model-wide)映射
  • 设置默认架构
  • 设置自定义约定
实体(Entity)映射
  • 设置单表或多表和设置架构
  • 设置复杂类型
  • 设置继承层次结构
属性(Property)映射
  • 设置列,列名、类型、是否可空、大小、排序
  • 设置并发列
  • 设置外键列
  • 配置关系

下面,我们开始使用Fluent API来配置领域类。

我们首先创建Student和Standard两个领域类,同样也创建出DbContext类,DbContext类中有个OnModelCreating方法,这里我们在它的继承类中把它覆写出来。

代码如下:

public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure domain classes using modelBuilder here base.OnModelCreating(modelBuilder);
}
}

使用Fluent API配置领域类时,所有的配置代码都要写在OnModelCreating方法里面,所有的领域类都可以在这个方法里面写上他们的初始化代码。程序初始化的时候,DataAnnotation和Fluent API的优先级是:Fluent API > DataAnnotations > 默认约定。

DbModelBuilder类包含了重要的用于配置的属性和方法,更多详情请翻阅MSDN文档。

接下来我们详细讲一些常用的Fluent API配置方法。

一、EntityTypeConfiguration类:

EntityTypeConfiguration类在Fluent API中有着重要的作用,它提供了一系列重要的方法和属性来覆写默认约定。

EntityTypeConfiguration类可以运行DbModelBuilder类的Entity<TEntity>()方法获得,如下所示:

EntityTypeConfiguration有下面这些重要的方法:

方法名 返回类型 描述
HasKey<TKey> EntityTypeConfiguration 为这个实体类型配置主键
HasMany<TTargetEntity> ManyNavigationPropertyConfiguration 为实体类型配置多对多关系
HasOptional<TTargetEntity> OptionalNavigationPropertyConfiguration

为实体类配置可选关系。没有指定关系的实体类型的实例会被存入数据库。数据库里外键可为空(nullable)。

HasRequired<TTargetEntity> RequiredNavigationPropertyConfiguration

为实体类型配置必须关系。除非关系确定,否则实体类型的实例不能存入数据库。数据库中的外键将不能为空(non-nullable)。

Ignore<TProperty> Void

从模型中排除一个属性,这个属性将不会映射到数据库。

Map EntityTypeConfiguration

允许高级配置有关该实体类型映射到数据库模式。

Property<T> StructuralTypeConfiguration

配置一个定义了这种类型的结构属性

ToTable Void

配置实体类型映射的表名

可以访问MSDN查询更多关于 EntityTypeConfiguration 类的信息。

下面介绍怎么用Fluent API配置实体类

二、Entity Mappings:

我们继续使用在学校应用里面的Student和Standard两个领域类

代码如下:

public class Student
{
public Student()
{ }
public int StudentID { 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 Standard Standard { get; set; }
} public class Standard
{
public Standard()
{ }
public int StandardId { get; set; }
public string StandardName { get; set; } public ICollection<Student> Students { get; set; } }
}

配置默认架构:

当我们想为一组特殊的表设置一个不同的构架时,可以使用HasDefaultSchema方法:

public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure default schema
modelBuilder.HasDefaultSchema("Admin");
}
}

映射实体到表:

Code-First将会为context类中的所有DbSet属性创建数据库表,表名就是属性名,比如上面的Students和Standards。我们也可以给表配置一个不同于DbSet属性名的表名,如下代码所示:

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure default schema
modelBuilder.HasDefaultSchema("Admin"); //Map entity to table
modelBuilder.Entity<Student>().ToTable("StudentInfo");
modelBuilder.Entity<Standard>().ToTable("StandardInfo","dbo"); }
}
}

如上代码,我们配置表名的ToTable方法是接在Entity<TEntity>()方法后面,上面代码已经把映射Student实体的表名改成StudentInfo,把映射Standard实体的表名改成了StandardInfo,特别留意的是,虽然我们把默认的架构名改成了Admin,但是Standard实体又特别指定了dbo架构,所以生成的数据库如下所示:

映射实体到多张表:

下面的代码演示了怎样把Student实体映射到数据库的多张表:

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>().Map(m =>
{
m.Properties(p => new { p.StudentId, p.StudentName});
m.ToTable("StudentInfo"); }).Map(m => {
m.Properties(p => new { p.StudentId, p.Height, p.Weight, p.Photo, p.DateOfBirth});
m.ToTable("StudentInfoDetail"); }); modelBuilder.Entity<Standard>().ToTable("StandardInfo"); }
}
}

如上所示,使用Map()方法可以映射Student实体的一些属性到StudentInfo表中,另一些属性到StudentInfoDetail表中,我们把Student实体分裂成了两张表,生成的数据库如下所示:

Map method need the delegate method as a parameter. You can pass  or in Map method, as shown below.

Map方法的传入参数是一个委托,具体可以参考 Action delegate 和 lambda expression

完成代码如下:

using System.Data.Entity.ModelConfiguration.Configuration;

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>().Map(delegate(EntityMappingConfiguration<Student> studentConfig)
{
studentConfig.Properties(p => new { p.StudentId, p.StudentName });
studentConfig.ToTable("StudentInfo");
}); Action<EntityMappingConfiguration<Student>> studentMapping = m =>
{
m.Properties(p => new { p.StudentId, p.Height, p.Weight, p.Photo, p.DateOfBirth });
m.ToTable("StudentInfoDetail");
};
modelBuilder.Entity<Student>().Map(studentMapping); modelBuilder.Entity<Standard>().ToTable("StandardInfo"); }
}
}

三、Property Mappings:

下面我们来介绍怎样用Fluent API配置实体类的属性

我们仍然使用学校的例子,如下两个Student和Standard领域类:

public class Student
{
public 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 Standard Standard { get; set; }
} public class Standard
{
public Standard()
{ }
public int StandardKey { get; set; }
public string StandardName { get; set; } public ICollection<Student> Students { get; set; } }
}

配置主键和混合主键:

上面的两个领域类,不能依据Code-First默认约定生成主键,因为它们没有Id或者{类名}+Id的属性,所以这里使用EntityTypeConfiguration类里的HasHey()方法来创建主键。

注意,modelBuilder.Entity<TEntity>()返回的是EntityTypeConfiguration对象。

public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure primary key
modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);
modelBuilder.Entity<Standard>().HasKey<int>(s => s.StandardKey); //Configure composite primary key
modelBuilder.Entity<Student>().HasKey<int>(s => new { s.StudentKey, s.StudentName });
}
}

配置列名、数据类型和排序:

Code-First默认约定以属性名为列名,下面的代码覆写了这一约定:

public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure Column
modelBuilder.Entity<Student>()
.Property(p => p.DateOfBirth)
.HasColumnName("DoB")
.HasColumnOrder()
.HasColumnType("datetime2");
}
}

如上所示,我们使用一个实体的Property()方法来配置列名、排序和数据类型

modelBuilder.Entity<TEntity>().Property(expression) 可以使用不同的方法来配置特别的属性,如下图所示:

为属性配置可空或不为空的列:

Code-First将为主键的数据类型创建一个不为空的值,因为主键本身就不能为空,除非它的属性上使用了?号或者标记了Nullable<T>。

使用IsOptional方法可以创建一个可为空的列,同样,使用IsRequired也可以创建一个不为空的列。

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure Null Column
modelBuilder.Entity<Student>()
.Property(p => p.Heigth)
.IsOptional(); //Configure NotNull Column
modelBuilder.Entity<Student>()
.Property(p => p.Weight)
.IsRequired();
}
}
}

配置列的大小:

Code-First默认约定是给列创建最大的数据类型大小,用HasMaxLength()方法覆写之。

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set StudentName column size to 50
modelBuilder.Entity<Student>()
.Property(p => p.StudentName)
.HasMaxLength(); //Set StudentName column size to 50 and change datatype to nchar
//IsFixedLength() change datatype from nvarchar to nchar
modelBuilder.Entity<Student>()
.Property(p => p.StudentName)
.HasMaxLength().IsFixedLength(); //Set size decimal(2,2)
modelBuilder.Entity<Student>()
.Property(p => p.Height)
.HasPrecision(, );
}
}
}

IsFixedLength方法把列的类型从nvarchar转变为nchar,HasPrecision方法改变了数据类型为decimal列的精度。

配置并发列:

使用ConcurrencyToken方法把一个属性设置为并发列,代码如下:

namespace CodeFirst_FluentAPI_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolDBContext(): base()
{
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set StudentName as concurrency column
modelBuilder.Entity<Student>()
.Property(p => p.StudentName)
.IsConcurrencyToken();
}
}
}

如上代码所示,StudentName被设置成为了并发列,每当update和delete操作的时候都会把StudentName中的值加入到SQL语句中的"where"子句中。

对于byte[]类型的属性,我们也可以用IsRowVersion()方法来将其配置成并发列。

到此,Fluent API的主要内容就讲的差不多了,下面开始会讲一对一,一对多,多对多的领域类配置,和数据库迁移等。

EntityFramework Code-First 简易教程(七)-------领域类配置之Fluent API的更多相关文章

  1. EntityFramework Code-First 简易教程(六)-------领域类配置之DataAnnotations

    EF Code-First提供了一个可以用在领域类或其属性上的DataAnnotation特性集合,DataAnnotation特性会覆盖默认的EF约定. DataAnnotation存在于两个命名空 ...

  2. EntityFramework Code-First 简易教程(五)-------领域类配置

    前言:在前篇中,总是把领域类(Domain Class)翻译成模型类,因为我的理解它就是一个现实对象的抽象模型,不知道对不对.以防止将来可能的歧义,这篇开始还是直接对Domain Class直译. 前 ...

  3. Entity Frame Code First 简易教程

    简介 什么是ORM 搭建Entity FrameWork CodeFirst应用 数据库迁移 表属性常见配置 Entity FrameWork 一对多.多对多 一.简介 Entity Framewor ...

  4. EntityFramework Code-First—领域类配置之DataAnnotations

    本文出自:https://www.cnblogs.com/tang-tang/p/5510574.html 一.摘要 EF Code-First提供了一个可以用在领域类或其属性上的DataAnnota ...

  5. WebGL简易教程(七):绘制一个矩形体

    目录 1. 概述 2. 示例 2.1. 顶点索引绘制 2.2. MVP矩阵设置 2.2.1. 模型矩阵 2.2.2. 投影矩阵 2.2.3. 视图矩阵 2.2.4. MVP矩阵 3. 结果 4. 参考 ...

  6. Spring Boot2 系列教程(七)理解自动化配置的原理

    Spring Boot 中的自动化配置确实够吸引人,甚至有人说 Spring Boot 让 Java 又一次焕发了生机,这话虽然听着有点夸张,但是不可否认的是,曾经臃肿繁琐的 Spring 配置确实让 ...

  7. EntityFramework Code-First 简易教程(十一)-------从已存在的数据库中映射出表

    怎样从一个已存在的数据库中映射表到 entity 实体? Entity Framework 提供了一个简便方法,可以为已存在的数据库里的所有表和视图创建实体类(entity class),并且可以用 ...

  8. Dart 语言简易教程系列

    google Fuchsia系统 及 dart语言简介 在 InteIIiJ IDEA 中搭建 Dart 的开发环境 Dart Linux 开发环境搭建 Dart 语言简易教程(一) Dart 语言简 ...

  9. EntityFramework 系列:实体类配置-根据依赖配置关系和关联

    EF实体类的配置可以使用数据注释或Fluent API两种方式配置,Fluent API配置的关键在于搞清实体类的依赖关系,按此方法配置,快速高效合理.为了方便理解,我们使用简化的实体A和B以及A.B ...

随机推荐

  1. [视频]K8软件破解脱壳入门教程

    [视频]K8软件破解脱壳入门教程 链接:https://pan.baidu.com/s/1aV9485MmtRedU6pzyr--Vw 提取码:vbak C:\Users\K8team\Desktop ...

  2. python之排序算法

    排序是每个语言都需要学会的,不管是c++.java还是python,套路都是类似的 python中也有自带的排序函数sort,直接使用也可 闲来无事写了几个排序算法,各不相同 1.每次遇到最小的数都交 ...

  3. Xamarin.Android 使用ListView绑定数据

    使用ListView进行数据绑定 第一步:新建一个类,用于存储显示字段. namespace ListViewDataBIndDemo { public class Person { public i ...

  4. Docker学习之4——构建NGINX镜像

    Nginx是一个高性能的Web和反向代理服务器,它具有很多非常优越的特性:1.作为Web服务器.2.作为负载均衡服务器.3.作为邮件代理服务器.4.安装及配置简单.接下来我们介绍在docker构建ng ...

  5. 根据PDF模板生成PDF文件(基于iTextSharp)

    根据PDF模板生成PDF文件,这里主要借助iTextSharp工具来完成.场景是这样的,假如要做一个电子协议,用过通过在线填写表单数据,然后系统根据用户填写的数据,生成电子档的协议.原理很简单,但是每 ...

  6. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十六):容器部署项目

    容器部署项目 这一章我们引入docker,采用docker容器的方式部署我们的项目. 首先需要有一个linux环境,并且安装 java 和 maven 以及 docker 环境,这个教程多如牛毛,不再 ...

  7. JAVA 面试知识点

    参考:https://www.cnblogs.com/java1024/p/8594784.html 反射: JAVA反射机制是在运行状态中, 对于任意一个类,都能够知道这个类的所有属性和方法: 对于 ...

  8. Maven教程1(介绍安装和配置)

    官网地址:http://maven.apache.org/ 1.Maven介绍 1.1为什么需要使用Maven 之前学Spring和SpringMVC的时候我们需要单独自己去找相关的jar. 这些ja ...

  9. PHP 网页数据api采集

    一个简单的数据采集,这里用的方法是API数据采集 //api地址,读取文本 $result = file_get_contents("https://feed.mix.sina.com.cn ...

  10. 自动化运维(2)之一键式单实例安装MySQL

    ZMySQLAutoTools文档 目标:自动化构建部署MySQL数据库,一键式单实例mysql安装,备份,监控,主从集群部署等.以及jdk,tomcat,nginx等基础中间件的自动化部署安装及运维 ...