• Code First 约定

  在前一篇中,我们已经知道了EF Code-First怎样从模型类(domain classes)中创建数据库表,下面,我们开始学习默认的Code-First约定。

什么是约定?

  约定就是在Code-First模式中自动配置模型类的默认规则,Code-First约定定义在System.Data.Entity.ModelConfiguration.Conventions 命名空间

让我们来看看各种约定的概述

类型发现(Type Discovery):

  在前一篇中,我们创建了一个context类并在其里面添加DbSet<T>属性,T为我们想要操作的模型类。Code-First会包括任何在这个类中的引用类型,就算这个引用类型的定义在其他不同集合中也是如此。

举个例子,下面的Student实体类有引用了Teacher类的属性,然而context并没有包含Teacher的DbSet属性。

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 Teacher Teacher { get; set; } public Standard Standard { get; set; }
} public class Teacher
{
public Teacher()
{ }
public int TeacherId { get; set; }
public string TeacherName { get; set; }
}

context并没有包含Teacher的DbSet属性

namespace EF_Code_First_Tutorials
{ public class SchoolContext: DbContext
{
public SchoolContext(): base()
{ } public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; } }
}

所以,即使Teacher类没有被包含在context的一个DbSet中,Code-First依然会创建一个Teachers表,如下图所示

即使context仅包含基类(base class)作为DbSet属性,Code-First也会包含它的派生类(derived class)

总结,类型发现(type discovery)约定是:

  1. Code-First 包含的类型作为一个DbSet属性被定义在context类中(Code-First includes types defined as a DbSet property in context class.)
  2. Code-First 包含的引用类型被包含在实体类型中,即使它被定义在不同的集合里(Code-First includes reference types included in entity types even if they are defined in different assembly.)
  3. Code-First 包含了派生类,即使只有它的基类作为DbSet属性被定义(Code-First includes derived classes even if only the base class is defined as DbSet property.)
  • 主键(Primary Key) 约定

  在上一篇中,我们看见Code-First自动在每张表里创建主键。这里的主键约定是:Code-First会自动把属性名称为Id或者<class name>Id(不区分大小写)的属性创建为主键,主键属性的数据类型可以是任何类型,但是如果主键属性的类型是数字或者GUID,则会将其定义成一个标识列(identity column)。

  如果你已经定义了键属性是除了Id或者<ClassName>Id的其他名称,则会抛出一个ModelValidationException异常,考虑如下代码

public class Standard
{
public Standard()
{ }
public int StdId { get; set; }
public string StandardName { get; set; } public IList<Student> Students { get; set; } }
}

如上所示,Standard类定义了StdId作为键属性,Entity Framework将抛出如下异常:

'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll
EntityType 'Standard' has no key defined. Define the key for this EntityType.

如果你非要定义StdId作为主键,那你必须使用DataAnnotations或者Fluent API去配置它成为主键,我们将在后面的章节学习到。

  • 关系(Relationship) 约定

  Code First使用导航属性(navigation property)在两个实体之间推断关系,导航属性是一种简单的引用类型或者集合类型。举个例子,我们在Student类中定义Standard导航属性,在Stardard类中定义ICollention<Student>导航属性,所以Code First可以自动在数据库中的Standards表和Students表之间创建一对多的关系并在Students表中插入Standard_StandardId外键列。

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; } //Navigation property
public Standard Standard { get; set; }
} public class Standard
{
public Standard()
{ }
public int StandardId { get; set; }
public string StandardName { get; set; } //Collection navigation property
public IList<Student> Students { get; set; } }

上面的实体使用Standard_StandardId作为外键创建如下关系

因此,默认的code first关系约定会自动插入外键,用<navigation property Name>_<primary key property name of navigation property type>这种格式,比如 Standard_StandardId

  • 外键(Foreign key) 约定

我们在上面看到了通过导航属性,Code Frist可以自动插入外键。但这里建议在关系末尾包含一个独立的外键属性。考虑如下代码:

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; } //Foreign key for Standard
public int StandardId { get; set; } public Standard Standard { get; set; }
} public class Standard
{
public Standard()
{ }
public int StandardId { get; set; }
public string StandardName { get; set; } public IList<Student> Students { get; set; } }

正如我们看到的,Student类包含了外键StandardId,而StandardId是Standard类的主键,现在,Code First将会在Students表中创建一个StandardId列来代替Standard_StandardId列,如下所示

注意:StandardId外键不能为空,因为int数据类型不可为空

Code First 根据不可为空的外键推断多重关系,除非外键属性为空然后关系被注册为空,否则,外键属性不为空(NOT NULL)。也可以把Student类StandardId属性的数据类型从int修改成Nullable<int>来创建一个外键可为空的Students表。

  • 复杂类型(Complex type) 约定

Code First 给类创建不包含键属性,而且主键没有被注册的复杂类型,这个时候使用DataAnnotation或者Fluent API。

  • 默认Code-First 约定表

Default Convention For Description
Table Name <Entity Class Name> + 's' 
EF will create DB table with entity class name suffixed by 's'
Primary key Name 1) Id 
2) <Entity Class Name> + "Id" (case insensitive)

EF will create primary key column for the property named Id or <Entity Class Name> + "Id" (case insensitive)

Foreign key property Name By default EF will look for foreign key property with the same name as principal entity primary key name. 
If foreign key property does not exists then EF will create FK column in Db table with <Dependent Navigation Property Name> + "_" + <Principal Entity Primary Key Property Name> 
e.g. EF will create Standard_StandardId foreign key column into Students table if Student entity does not contain foreignkey property for Standard where Standard contains StandardId
Null column EF creates null column for all reference type properties and nullable primitive properties.
Not Null Column EF creates NotNull columns for PrimaryKey properties and non-nullable value type properties.
DB Columns order EF will create DB columns same as order of properties in an entity class. However, primary key columns would be moved first.
Properties mapping to DB By default all properties will map to database. Use [NotMapped] attribute to exclude property or class from DB mapping.
Cascade delete Enabled By default for all types of relationships.

下面的表列出了C#数据类型映射到SQL的数据类型,和主键列的数据类型以及长度

C# DataType Related DB Column DataType PK Column DataType & Length
int int int, Identity column increment by 1
string nvarchar(Max) nvarchar(128)
decimal decimal(18,2) decimal(18,2)
float real real
byte[] varbinary(Max) varbinary(128)
datetime datetime datetime
bool bit bit
byte tinyint tinyint
short smallint smallint
long bigint bigint
double float float
char No mapping No mapping
sbyte No mapping 
(throws exception)
No mapping
object No mapping No mapping

这是篇对code first约定的概述,这里的约定也能用DataAnnotation和Fluent API重写。在EF6.0里,你也可以使用自定义约定。

学完这篇,相信大家也对“约定大于配置”这种设计理念也有感知了吧^_^

下一篇我们将学习怎样初始化数据库,嗯,先睡觉了

EntityFramework Code-First 简易教程(二)-------Code First约定的更多相关文章

  1. WebGL简易教程(二):向着色器传输数据

    目录 1. 概述 2. 示例:绘制一个点(改进版) 1) attribute变量 2) uniform变量 3) varying变量 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL ...

  2. Entity Frame Code First 简易教程

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

  3. PySide 简易教程<二>-------工欲善其事,必先利其器

    OK , 在Linux的开发环境下,对于我们的简短的PySide程序而言,不需要使用QtCreator,使用文本编辑器.之所以,使用文本编辑器,是因为小应用代码量很少,更重要的是一行行的写可以加深我们 ...

  4. Dart 语言简易教程系列

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

  5. WebGL简易教程(三):绘制一个三角形(缓冲区对象)

    目录 1. 概述 2. 示例:绘制三角形 1) HelloTriangle.html 2) HelloTriangle.js 3) 缓冲区对象 (1) 创建缓冲区对象(gl.createBuffer( ...

  6. WebGL简易教程(四):颜色

    目录 1. 概述 2. 示例:绘制三角形 1) 数据的组织 2) varying变量 3. 结果 4. 理解 1) 图形装配和光栅化 2) 内插过程 5. 参考 1. 概述 在上一篇教程<Web ...

  7. WebGL简易教程——目录

    目录 1. 绪论 2. 目录 3. 资源 1. 绪论 最近研究WebGL,看了<WebGL编程指南>这本书,结合自己的专业知识写的一系列教程.之前在看OpenGL/WebGL的时候总是感觉 ...

  8. mysql进阶(二)索引简易教程

    Mysql索引简易教程 基本概念 索引是指把你设置为索引的字段A的内容储存在一个独立区间S里,里面只有这个字段的内容.在找查这个与这个字段A的内容时会直接从这个独立区间里查找,而不是去到数据表里查找. ...

  9. Ocelot简易教程(二)之快速开始2

    为什么这篇的标题叫"Ocelot简易教程(二)之快速开始2"呢,因为很多朋友跟我说上一篇" Ocelot简易教程(二)之快速开始1"内容太少了,只是简单介绍Oc ...

  10. Ocelot简易教程(二)之快速开始1

    Ocelot简易教程目录 Ocelot简易教程(一)之Ocelot是什么 Ocelot简易教程(二)之快速开始1 Ocelot简易教程(二)之快速开始2 Ocelot简易教程(三)之主要特性及路由详解 ...

随机推荐

  1. [Python 从入门到放弃] 1. 列表的基本操作

    ''' 列表 Create By 阅后即焚 On 2018.1.29 ''' 1. 列表的定义 列表看起来好像其它编程语言中的数组,但列表具备更加强大的功能,它是Python完备的集合对象,现在,你可 ...

  2. docker(一)

    一.docker 概述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 linux 机器上,也可以实现虚拟化.容器是完全使用沙箱 ...

  3. GitHub多人协作简明教程

    本文面向已经了解/熟悉git基本命令但是并不熟悉如何使用GitHub进行多人协作开发项目的同学. 为了简单起见,这里假设只有两个开发人员,HuanianLi 和 DaxiangLi.他们在GitHub ...

  4. 带你了解CSRF和XSS(二)

    什么是CSRF? CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XS ...

  5. CodeForces -977F(突破定式思维+map应用)

    题目链接: https://cn.vjudge.net/problem/CodeForces-977F /* 问题 输入n和n个数的数列 计算并输出最长增量为1的上升子序列 解题思路 用n2的最长上升 ...

  6. core Animation之CAKeyframeAnimation(关键帧动画)

    CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSA ...

  7. Netty 核心组件 EventLoop 源码解析

    前言 在前文 Netty 启动过程源码分析 (本文超长慎读)(基于4.1.23) 中,我们分析了整个服务器端的启动过程.在那篇文章中,我们重点关注了启动过程,而在启动过程中对核心组件并没有进行详细介绍 ...

  8. Docker基础-端口映射与容器互联

    1.端口映射实现访问容器 1.从外部访问容器应用 在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内部的网络应用和服务的. 当容器中运行一些网络应用,要让外部访问这些应用时, ...

  9. android studio 断网使用

  10. Asp.net core WebApi 使用Swagger生成帮助页实例

    最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效 ...