转自:http://blog.163.com/m13864039250_1/blog/static/2138652482015283397609/

用Fluent API 配置/映射属性和类型

简介

通常通过重写派生DbContext 上的OnModelCreating 方法来访问Code First Fluent API。以下示例旨在显示如何使用 Fluent API 执行各种任务,您可以将代码复制出来并进行自定义,使之适用于您的模型。

属性映射

Property 方法用于为每个属于实体或复杂类型的属性配置特性。Property 方法用于获取给定属性的配置对象。配置对象上的选项特定于要配置的类型;例如,IsUnicode 只能用于字符串属性。

配置主键

要显式将某个属性设置为主键,可使用 HasKey 方法。在以下示例中,使用了 HasKey 方法对 OfficeAssignment 类型配置 InstructorID 主键。

modelBuilder.Entity<OfficeAssignment>().HasKey(t =>t.InstructorID);

配置组合主键

以下示例配置要作为Department 类型的组合主键的DepartmentID 和 Name 属性。

modelBuilder.Entity<Department>().HasKey(t => new { t.DepartmentID, t.Name });

关闭数值主键的标识

以下示例将DepartmentID 属性设置为System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None,以指示该值不由数据库生成。

modelBuilder.Entity<Department>().Property(t =>t.DepartmentID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

指定属性的最大长度

在以下示例中,Name属性不应超过 50 个字符。如果其值超过 50 个字符,则出现 DbEntityValidationException 异常。如果 Code First 基于此模型创建数据库,它还会将 Name 列的最大长度设置为50 个字符。

modelBuilder.Entity<Department>().Property(t =>t.Name).HasMaxLength(50);

将属性配置为必需

在下面的示例中,Name属性是必需的。如果不指定 Name,则出现 DbEntityValidationException 异常。如果 Code First 基于此模型创建数据库,则用于存储此属性的列将不可为空。

modelBuilder.Entity<Department>().Property(t =>t.Name).IsRequired();

指定不将CLR 属性映射到数据库中的列

以下示例显示如何指定CLR 类型的属性不映射到数据库中的列。

modelBuilder.Entity<Department>().Ignore(t => t.Budget);

将CLR 属性映射到数据库中的特定列

以下示例将Name CLR 属性映射到DepartmentName 数据库列。

modelBuilder.Entity<Department>().Property(t =>t.Name).HasColumnName("DepartmentName");

重命名模型中未定义的外键

如果您选择不对CLR 类型定义外键,但希望指定它在数据库中应使用的名称,请编码如下:

modelBuilder.Entity<Course>()

.HasRequired(c => c.Department)

.WithMany(t => t.Courses)

.Map(m => m.MapKey("ChangedDepartmentID"));

配置字符串属性是否支持Unicode 内容

默认情况下,字符串为Unicode(SQLServer 中的nvarchar)。您可以使用IsUnicode 方法指定字符串应为varchar 类型。

modelBuilder.Entity<Department>()

.Property(t => t.Name)

.IsUnicode(false);

配置数据库列的数据类型

HasColumnType 方法支持映射到相同基本类型的不同表示。使用此方法并不支持在运行时执行任何数据转换。请注意,IsUnicode 是将列设置为 varchar 的首选方法,因为它与数据库无关。

modelBuilder.Entity<Department>()

.Property(p => p.Name)

.HasColumnType("varchar");

配置复杂类型的属性

对复杂类型配置标量属性有两种方法。

可以对ComplexTypeConfiguration 调用Property。

modelBuilder.ComplexType<Details>()

.Property(t => t.Location)

.HasMaxLength(20);

也可以使用点表示法访问复杂类型的属性。

modelBuilder.Entity<OnsiteCourse>()

.Property(t => t.Details.Location)

.HasMaxLength(20);

将属性配置为用作乐观并发令牌

要指定实体中的某个属性表示并发令牌,可使用 ConcurrencyCheck 特性或 IsConcurrencyToken 方法。

modelBuilder.Entity<OfficeAssignment>()

.Property(t => t.Timestamp)

.IsConcurrencyToken();

也可以使用IsRowVersion 方法将属性配置为数据库中的行版本。将属性设置为行版本会自动将它配置为乐观并发令牌。

modelBuilder.Entity<OfficeAssignment>()

.Property(t => t.Timestamp)

.IsRowVersion();

类型映射

将类指定为复杂类型

按约定,没有指定主键的类型将被视为复杂类型。在一些情况下,Code First 不会检测复杂类型(例如,如果您有名为“ID”的属性,但不想将它用作主键)。在此类情况下,您将使用 Fluent API 显式指定某类型是复杂类型。

modelBuilder.ComplexType<Details>();

指定不将CLR 实体类型映射到数据库中的表

以下示例显示如何排除一个 CLR 类型,使之不映射到数据库中的表。

modelBuilder.Ignore<OnlineCourse>();

将CLR 实体类型映射到数据库中的特定表

Department 的所有属性都将映射到名为 t_ Department 的表中的列。

modelBuilder.Entity<Department>().ToTable("t_Department");

您也可以这样指定架构名称:

modelBuilder.Entity<Department>().ToTable("t_Department", "school");

映射“每个层次结构一张表(TPH)”继承

在 TPH 映射情形下,继承层次结构中的所有类型都将映射到同一个表。鉴别器列用于标识每行的类型。使用 Code First 创建模型时,TPH 参与继承层次结构的类型所用的默认策略。默认情况下,鉴别器列将添加到名为“Discriminator”的表,且层次结构中每个类型的 CLR 类型名称都将用作鉴别器值。可以使用 Fluent API 修改默认行为。

modelBuilder.Entity<Course>()

.Map<Course>(m=> m.Requires("Type").HasValue("Course"))

.Map<OnsiteCourse>(m=> m.Requires("Type").HasValue("OnsiteCourse"));

映射“每个类型一张表(TPT)”继承

在 TPT 映射情形下,所有类型分别映射到不同的表。仅属于某个基类型或派生类型的属性存储在映射到该类型的一个表中。映射到派生类型的表还会存储一个将派生表与基表联接的外键。

modelBuilder.Entity<Course>().ToTable("Course");

modelBuilder.Entity<OnsiteCourse>().ToTable("OnsiteCourse");

映射“每个具体类一张表(TPC)”继承

在 TPC 映射情形下,层次结构中的所有非抽象类型分别映射到不同的表。映射到派生类的表与映射到数据库中基类的表并无关系。类的所有属性(包括继承属性)都将映射到相应表的列。

调用MapInheritedProperties 方法来配置每个派生类型。MapInheritedProperties 将继承自基类的所有属性重新映射到派生类的表中的新列。

注意:因为属于TPC 继承层次结构的表并不使用同一个主键,因此,如果您让数据库生成的值具有相同标识种子,则在映射到子类的表中执行插入操作时,会产生重复的实体键。要解决此问题,可以为每个表指定不同的初始种子值,或关闭主键属性的标识。当使用 Code First 时,标识就是整数键属性的默认值。

modelBuilder.Entity<Course>()

.Property(c => c.CourseID)

.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

modelBuilder.Entity<OnsiteCourse>().Map(m =>

{

m.MapInheritedProperties();

m.ToTable("OnsiteCourse");

});

modelBuilder.Entity<OnlineCourse>().Map(m =>

{

m.MapInheritedProperties();

m.ToTable("OnlineCourse");

});

将实体类型的CLR 属性映射到数据库中的多个表(实体拆分)

实体拆分允许一个实体类型的属性分散在多个表中。在以下示例中,Department 实体拆分到两个表中:Department 和DepartmentDetails。实体拆分通过多次调用 Map 方法将一部分属性映射到特定表。

modelBuilder.Entity<Department>()

.Map(m=>

{

m.Properties(t => new{ t.DepartmentID, t.Name });

m.ToTable("Department");

})

.Map(m=>

{

m.Properties(t=> new { t.DepartmentID, t.Administrator,t.StartDate, t.Budget });

m.ToTable("DepartmentDetails");

});

将多个实体类型映射到数据库中的一个表(表拆分)

以下示例将使用同一个主键的两个实体类型映射到同一个表。

modelBuilder.Entity<OfficeAssignment>()

.HasKey(t => t.InstructorID);

modelBuilder.Entity<Instructor>()

.HasRequired(t => t.OfficeAssignment)

.WithRequiredPrincipal(t =>t.Instructor);

modelBuilder.Entity<Instructor>().ToTable("Instructor");

modelBuilder.Entity<OfficeAssignment>().ToTable("Instructor");

使用FluentAPI配置关系

简介

使用FluentAPI配置关系的时候,首先要获得一个EntityTypeConfiguration实例,然后使用其上的HasRequired, HasOptional或者 HasMany方法来指定当前实体参与的关系类型。HasRequired 和HasOptional方法需要一个lambda表达式来指定一个导航属性,HasMany方法需要一个lambda表达式指定一个集合导航属性。然后可以使用WithRequired, WithOptional和WithMany方法来指定反向导航属性,这些方法有不带参数的重载用来指定单向导航。

之后还可以使用HasForeignKey方法来指定外键属性。

配置【必须-可选】关系(1-0..1)

OfficeAssignment的键属性不符合命名约定,所以需要我们显式指定。下面的关系表明,OfficeAssignment的Instructor必须存在,但是Instructor的OfficeAssignment不是必须存在的。

modelBuilder.Entity<OfficeAssignment>()

.HasKey(t => t.InstructorID);

// Map one-to-zero or one relationship

modelBuilder.Entity<OfficeAssignment>()

.HasRequired(t => t.Instructor)

.WithOptional(t => t.OfficeAssignment);

配置两端都是必须的关系(1-1)

大多数情况下,EF都能推断哪一个类型是依赖项或者是主体项。然而当关系的两端都是必须的或者都是可选的,那么EF就不能识别依赖项或者是主体项。如果关系两端都是必须的,那么在HasRequired方法后使用WithRequiredPrincipal或者WithRequiredDependent来确定主体。如果关系两端都是可选的,那么在HasRequired方法后使用WithOptionalPrincipal和WithOptionalDependent。

modelBuilder.Entity<OfficeAssignment>()

.HasKey(t => t.InstructorID);

modelBuilder.Entity<Instructor>()

.HasRequired(t => t.OfficeAssignment)

.WithRequiredPrincipal(t => t.Instructor);

配置多对多关系

下面的代码配置了一个多对多关系,CodeFirst会使用命名约定来创建连接表,命名约定会使用Course_CourseID 和 Instructor_InstructorID作为连接表的列。

modelBuilder.Entity<Course>()

.HasMany(t => t.Instructors)

.WithMany(t => t.Courses);

如果想指定连接表的表名和列名,需要使用Map方法,如下:

modelBuilder.Entity<Course>()

.HasMany(t => t.Instructors)

.WithMany(t => t.Courses)

.Map(m =>

{

m.ToTable("CourseInstructor");

m.MapLeftKey("CourseID");

m.MapRightKey("InstructorID");

});

配置单向导航属

所谓单向导航属性指的是只在关系的一端定义了导航属性。按照约定,CodeFirst将单向导航理解为一对多关系,如果需要一对一的单向导航属性,需要使用如下方法:

modelBuilder.Entity<OfficeAssignment>()

.HasKey(t => t.InstructorID);

modelBuilder.Entity<Instructor>()

.HasRequired(t => t.OfficeAssignment)

.WithRequiredPrincipal();

启用级联删除

使用WillCascadeOnDelete方法来配置关系是否允许级联删除。如果外键是不可空的,CodeFirst默认会设置级联删除;否则,不会设置级联删除,当主体被删除后,外键将会被置空。

可以使用如下代码移除此约定:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

下面的代码片段配置为外键不能为空,而且禁用了级联删除。

modelBuilder.Entity<Course>()

.HasRequired(t => t.Department)

.WithMany(t => t.Courses)

.HasForeignKey(d => d.DepartmentID)

.WillCascadeOnDelete(false);

配置组合外键

下面的代码配置了组合外键

modelBuilder.Entity<Department>()

.HasKey(d => new{ d.DepartmentID, d.Name });

// Composite foreign key

modelBuilder.Entity<Course>()

.HasRequired(c => c.Department)

.WithMany(d => d.Courses)

.HasForeignKey(d => new { d.DepartmentID, d.DepartmentName });

配置不符合命名约定的外键属性

SomeDepartmentID属性不符合外键命名约定,需要使用如下方法将其设置为外键属性:

modelBuilder.Entity<Course>()

.HasRequired(c => c.Department)

.WithMany(d => d.Courses)

.HasForeignKey(c =>c.SomeDepartmentID);

Code First约定-Fluent API配置的更多相关文章

  1. 使用Fluent API 配置/映射属性和类型

    Code First约定-Fluent API配置 使用Fluent API 配置/映射属性和类型 简介 通常通过重写派生DbContext 上的OnModelCreating 方法来访问Code F ...

  2. Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

    在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...

  3. Entity Framework Code First (五)Fluent API - 配置关系

    上一篇文章我们讲解了如何用 Fluent API 来配置/映射属性和类型,本文将把重点放在其是如何配置关系的. 文中所使用代码如下 public class Student { public int ...

  4. Entity Framework Code First (五)Fluent API - 配置关系 转载 https://www.cnblogs.com/panchunting/p/entity-framework-code-first-fluent-api-configuring-relationships.html

    上一篇文章我们讲解了如何用 Fluent API 来配置/映射属性和类型,本文将把重点放在其是如何配置关系的. 文中所使用代码如下 public class Student { public int ...

  5. 使用 Fluent API 配置/映射属性和类型(摘自微软Data Access and Storage)

    使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...

  6. Code First 关系 Fluent API

    通过实体框架 Code First,可以使用您自己的域类表示 EF 执行查询.更改跟踪和更新函数所依赖的模型.Code First 利用称为“约定先于配置”的编程模式.这意味着 Code First ...

  7. 使用 Fluent API 配置/映射属性和类型

    使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...

  8. 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...

  9. EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射

    I.EF里的默认映射 上篇文章演示的通过定义实体类就可以自动生成数据库,并且EF自动设置了数据库的主键.外键以及表名和字段的类型等,这就是EF里的默认映射.具体分为: 数据库映射:Code First ...

随机推荐

  1. 2017-3-2 C#基础 结构体

    1. 结构体:用户自定义类型定义位置:定义在Main函数的外面,类的里面 定义格式:struct 自定义名字{ public 数据类型 名字; public 数据类型 名字; ... ...} 声明实 ...

  2. windows service宿主web api使用"依赖注入"和“控制反转”的技术实践

    前言 自从几年前抛弃wcf,使用web api 来做服务器端开发之后,就不再迷惑了.但是因为本来从事传统行业管理软件开发,一般都以分布式应用开发为主.纯BS还是比较少,于是比较喜欢用windows s ...

  3. C#语言基础——语句

    1·语句是指程序命令,都是按照顺序执行的.语句在程序中的执行顺序称为"控制流"或"执行流".根据程序对运行时所收到的输入的响应,在程序每次执行时控制流可能有所不 ...

  4. 使用multer搭建一个图片接收服务器

    为了测试图片上传插件的上传功能是否好用,最近尝试搭建了一个接收图片的服务器,因为图片上传的编码格式是form-data,所以我选择使用express+multer,实现过程中发现有几个需要注意的地方, ...

  5. 在Windows平台搭建轻巧的Python开发环境——面向工程和科研的扩展包配置

    首先,下载最新版本的Python. 为什么强调最新版本呢,因为新版本的漏洞通常会少得多,而且反映了未来的趋势. 既然要学,何不起点高一点? 官方下载地址:https://www.python.org/ ...

  6. Collector for ArcGIS的使用体验

    基于Esri的Portal for ArcGIS(下面简称Portal),用户可以搭建一个本地的地理信息云平台.围绕着这个云平台,Esri为不同的终端提供了响应的解决方案,其中Collector fo ...

  7. 1677: [Usaco2005 Jan]Sumsets 求和

    1677: [Usaco2005 Jan]Sumsets 求和 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 626  Solved: 348[Submi ...

  8. Spark2.1集群安装(standalone模式)

    机器部署 准备三台Linux服务器,安装好JDK1.7 下载Spark安装包 上传spark-2.1.0-bin-hadoop2.6.tgz安装包到Linux(intsmaze-131)上 解压安装包 ...

  9. JQ鼠标右键点击功能 兼容IE8

    //阻止浏览器当前DIV默认右键事件 $("div").unbind("mousedown").bind("contextmenu", fu ...

  10. java学习笔记 --- 条件,循环语句

    一.三元运算符 A:格式    比较表达式?表达式1:表达式2;   B:执行流程:    首先计算比较表达式的值,看是true还是false.    如果是true,表达式1就是结果.    如果是 ...