Code First约定-Fluent API配置

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

简介

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

属性映射

使用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);

展开全文

使用Fluent API 配置/映射属性和类型的更多相关文章

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

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

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

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

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

    1.将多个实体类映射到数据库中的一个表 要将多个实体映射到一个数据库表需要满足: a. 两个实体必须是一对一关系 b.两个实体共享一个主键 public class MyContext:DbConte ...

  4. EF使用Fluent API配置映射关系

    定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射. 映 ...

  5. Code First约定-Fluent API配置

    转自:http://blog.163.com/m13864039250_1/blog/static/2138652482015283397609/ 用Fluent API 配置/映射属性和类型 简介 ...

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

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

  7. 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 ...

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

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

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

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

随机推荐

  1. MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令

    介绍背水一战 Windows 10 之 MVVM(Model-View-ViewModel) 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令 ...

  2. 解决PHP生成UTF-8编码的CSV文件用Excel打开乱码的问题

    在要输出的内容前先输出"\xEF\xBB\xBF", eg:要输出的内容保存在$content里$content = "\xEF\xBB\xBF".$conte ...

  3. Java实现本地 fileCopy

    前言: Java中流是重要的内容,基础的文件读写与拷贝知识点是很多面试的考点.故通过本文进行简单测试总结. 2.图展示[文本IO/二进制IO](这是参考自网上的一张总结图,相当经典,方便对比记忆) 3 ...

  4. 快速查找无序数组中的第K大数?

    1.题目分析: 查找无序数组中的第K大数,直观感觉便是先排好序再找到下标为K-1的元素,时间复杂度O(NlgN).在此,我们想探索是否存在时间复杂度 < O(NlgN),而且近似等于O(N)的高 ...

  5. angularjs 自带的过滤器

    一,内置的过滤器 1,uppercase,lowercase大小转换 {{ "lower cap string" | uppercase }}     //结果:LOWER CAP ...

  6. 回合对战制游戏第一篇(初识java)

    回合对战制游戏第一篇 一,所谓的java. java是一门完全面向对象的编程语言,而之前所接触到的C语言是一门面向有一个过程的语音,对于两个的区别应该有一个清楚的认识. java的第一个内容. 类和对 ...

  7. javaweb项目打包成war包

    从来没有想过web项目还能打包的,但是有要求,就不得不去实现,在网上找了一下,发现挺简单的. 首先是使用MyEclipse将web项目打包,如下图所示. 右键选中项目,选择export. 然后选择J2 ...

  8. 【caffe】无法找到gpu/mxGPUArray.h: No such file or directory

    @tags: caffe 问题出现在,windows下编译caffe的过程中.按照github.com/microsoft/caffe的readme配置的. 问题原因是,用的matlab版本较新(20 ...

  9. 【codevs1170】 双栈排序

    http://codevs.cn/problem/1170/ (题目链接) 题意 给出一个初始序列,判断能否通过两个栈的入栈和出栈操作构造出一个有序序列.若可以,输出字典序最小的方案. Solutio ...

  10. Linux内核邮件列表发送和回复格式研究

    1.使用的内容格式为[纯文本],这个在国内的客户端已经没有了,大公司只有微软的outlook. 2.回复引用时,使用符号[>]作为标记,且回复的内容不能在最顶部,应该在最下面.参考:http:/ ...