EntityFramework Code-First 简易教程(二)-------Code First约定

  • 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里,你也可以使用自定义约定。

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

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

时间: 2024-10-05 03:35:26

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

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

目录 1. 概述 2. 示例:绘制一个点(改进版) 1) attribute变量 2) uniform变量 3) varying变量 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL简易教程(一):第一个简单示例>中,通过一个绘制点的例子,对WebGL中的可编程渲染管线有了个基本的认识.在之前绘制点的例子中,点的位置,点的大小,点的颜色,都是固定写在着色器中的,这样的程序是缺乏可扩展性的. 比如我想绘制一张地形(DEM),平时地形数据是保存在地形文件之中的.被程序加载之后,数据信息

WebGL简易教程(四):颜色

目录 1. 概述 2. 示例:绘制三角形 1) 数据的组织 2) varying变量 3. 结果 4. 理解 1) 图形装配和光栅化 2) 内插过程 5. 参考 1. 概述 在上一篇教程<WebGL简易教程(三):绘制一个三角形(缓冲区对象)>中,通过使用缓冲区对象(buffer object)来向顶点着色器传送数据.那么,如果这些数据(与顶点相关的数据,如法向量.颜色等)需要继续传送到片元着色器该怎么办呢? 例如这里给三角形的每个顶点赋予不同的颜色,绘制一个彩色的三角形.这个时候就需要用到之

Code Complete阅读笔记(二)

2015-03-06   328   Unusual Data Types    ——You can carry this technique to extremes,putting all the variables in your program into one big,juicy variable and then passingit everywhere.Careful programmers avoid bundling data any more than is logically

Vs Code 插件配置教程

1 Vs Code 下载地址:https://code.visualstudio.com/ 2   安装好Vs Code,点击启动,点击File-> Open Folder 打开项目 3 点击Extensions 输入插件的名称,然后Install 安装插件.插件安装完成后点击Reload,插件生效. 4 主题插件需要在File->Preferences->选对应的插件名称,部分功能插件可以使用快捷键 Ctrl+shift+p,输入对应的功能名字执行,使用. 5 必备插件推荐:http:

WebGL简易教程(十二):包围球与投影

目录 1. 概述 2. 实现详解 3. 具体代码 4. 参考 1. 概述 在之前的教程中,都是通过物体的包围盒来设置模型视图投影矩阵(MVP矩阵),来确定物体合适的位置的.但是在很多情况下,使用包围盒并不方便计算,可以利用包围盒再生成一个包围球,利用包围球来设置MVP矩阵. 在<WebGL简易教程(十):光照>中,给地形赋予了固定方向的平行光.这篇教程的例子就是想模拟在平行光的视角下地形的情况.对于点光源光,可以用透视投影来实现渲染的效果:而平行光就需要通过正射投影来模拟.并且,这种正射并不是

文件上传利器SWFUpload入门简易教程

凡做过网站开发的都应该知道表单file的确鸡肋. Ajax解决了不刷新页面提交表单,但是却没有解决文件上传不刷新页面,当然也有其它技术让不刷新页面而提交文件,该技术主要是利用隐藏的iFrame, 较Ajax要麻烦许多,而且其提交方式依然在底层是使用的表单file,这里我们不详谈.而且如果是提交较小的文件,我们能接受,如果提交的文件较大,我 们便要忍受很长的等待时间,而浏览器却没有任何提示,我们也没有办法知道文件上传的进度… 但是现在,网上出现了一个名为SWFUpload的上传组件,该组件利用Fl

CRL快速开发框架系列教程二(基于Lambda表达式查询)

本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框架系列教程四(删除数据) CRL快速开发框架系列教程五(使用缓存) CRL快速开发框架系列教程六(分布式缓存解决方案) CRL快速开发框架系列教程七(使用事务) CRL快速开发框架系列教程八(使用CRL.Package) CRL快速开发框架系列教程九(导入/导出数据) CRL快速开发框架系列教程十(

EntityFramework 5.0 CodeFirst 教程02-删除和修改/架构改变异常的处理

-----------------------------------------------------目录----------------------------------------------------- EntityFramework 5.0 CodeFirst 教程01-搭建环境和快速上手 (2015-07-13 10:48) EntityFramework 5.0 CodeFirst 教程02-删除和修改/架构改变异常的处理 (2015-07-14 17:50) -------

EntityFramework 5.0 CodeFirst 教程01-搭建环境和快速上手

----------------------------目录------------------------------ EntityFramework 5.0 CodeFirst 教程01-搭建环境和快速上手 ----------------------------目录------------------------------ 网上关于EntityFramework 5.0的教程很多,但是大多数都是代码整理不清晰,有些甚至是拷贝,代码丢失等问题,本人最近也有一个项目是用到EntityFram

EntityFramework 5.0 CodeFirst 教程03-数据结构的定义/列的属性

---------------------目录-------------------------- EntityFramework 5.0 CodeFirst 教程03-数据结构的定义/列的属性 (2015-07-22 17:30) EntityFramework 5.0 CodeFirst 教程02-删除和修改/架构改变异常的处理 (2015-07-14 17:50) EntityFramework 5.0 CodeFirst 教程01-搭建环境和快速上手 (2015-07-13 10:48)