Entity Framework 简言之就是一个ORM(Object-Relational Mapper)框架.
Code First 使得你能够通过C#的类来描述一个模型,模型如何被发现/检测就是通过一些约定(Conventions)。Conventions 就是一系列规则的集合,被用于对基于类别定义的概念模型的自动装配。
这些约定都被定义于 System.Data.Entity.ModelConfiguration.Conventions 命名空间下。
当然你可以进一步地对你的模型作出配置,例如使用 Data Annotations 或者 Fluent API. 推荐的配置顺序如下:优先使用 Data Annotations ,然后是 Fluent API ,最后才是 Conventions.
本文将会给出一个关于 Conventions 的初步介绍,具体详细的列表请参考
一、类型发现约定 Type Discovery
当我们使用 Entity Framework 进行开发的时候,通常是以构建一些定义概念模型的类开始,除此之外,我们还需要让 DbContext 知道哪些类型需要包含在此模型中,为了达到此目的,我们又会定义一个继承自 DbContext 并且为这些类型暴露 DbSet 属性。这样 Code First 将包含这些类型以及这些类型的引用类型(即便引用类型定义于不同的程序集中)
如果类型位于继承体系中,也只需为基类(base class)定义 DbSet 属性,那么位于同一程序集中的派生类型也将被自动包含与其中。
下面的例子中,在类 SchoolEntities 中只定义了一个 DbSet 属性 Departments . Code First 能够发现并钻取所有的引用类型
using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Web;namespace ContosoUniversity.DAL{ public class SchoolEntities : DbContext { public DbSetDepartments { get; set; } } public class Department { // Primary key public int DepartmentID { get; set; } public string Name { get; set; } // Navigation property public virtual ICollection Courses { get; set; } } public class Course { // Primary key public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } // Foreign key public int DepartmentID { get; set; } // Navigation properties public virtual Department Department { get; set; } } public partial class OnlineCourse : Course { public string URL { get; set; } } public partial class OnsiteCourse : Course { public string Location { get; set; } public string Days { get; set; } public System.DateTime Time { get; set; } }}
如果你想排除模型中的某个类型,你可以使用 NotMapped 属性(Attribute)或者 DbModelBuilder.Ignore fluent API.
[NotMapped] public class Department
NotMapped 位于 System.ComponentModel.DataAnnotations.Schema 命名空间下
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Ignore(); }
二、主键约定 Primary Key Convention
如果类中的属性(Property)名称为 ID (不区分大小写)或 ClassNameID(类名 + ID),Code First 则推断这个属性为主键。如果主键属性的类型为数字型或 GUID 则会被当成标识列(Identity Column)
public class Department { //Primary key public int ID { get; set; } //Primary key public int DepartmentID { get; set; } }
三、关系(外键/导航属性)约定 Relationship(Foreign Key/Navigation Properties) Convention
在 Entity Framework 中,导航属性(Navigation Properties)提供了一种对两个实体类型之间关系的驱动,每一个对象都能拥有它所参与的每一个关系的导航属性(每一个对象的每一个关系都能有一个导航属性),导航属性提供在两端来驱动或操作这个关系,也可以返回任何一方的引用对象(对象间的关系是 1:1 或者 1:0 )或 对象的集合(对象间的关系为 1:* 或 *:*), Code First 根据定义于类型上的导航属性能够推断这种关系
除了导航属性外,推荐的方式是再包含外键属性(Foreign Key)。Code First 能够推断如下的命名属性为外键(外键属性命名的默认约定):
- <导航属性名><主体主键属性名>;
- <主体类名><主键属性名>;
- <主体主键属性名>
优先顺序为从上到下(多个满足匹配/约定的时候)。外键属性命名约定也是大小写不敏感的。(PS: 个人觉得把 Principal 译为主体,Dependent Entity 译为从属实体较为稳妥,分别对应主从关系)
当外键属性被检测到,Code First 将会根据外键的可空性来推断关系的具体形式:如果属性是可空的,那么关系将被注册为可选的;否则则被认为是必须的。
如果从属实体上的外键是不可为空的,Code First 将会在关系上设置级联删除,反之,则不会级联删除,并且当主体被删除的时候,外键将会被置为 NULL
多说一句:以上所说的关系多重性(multiplicity)和级联删除可以被 Fluent API 重载(覆写)
以下示例展示用导航属性和外键来定义类 Department 和 Course 之间的关系
public class Department { // Primary key public int DepartmentID { get; set; } public string Name { get; set; } // Navigation property public virtual ICollectionCourses { get; set; } } public class Course { // Primary key public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } // Foreign key public int DepartmentID { get; set; } // Navigation properties public virtual Department Department { get; set; } }
四、Complex Types Conventions
如果 Code First 无法从类定义中推断出主键,也没有通过 Data Annotations 或 Fluent API 注册的主键,则此类型自动注册为 Complex Types. Complex Types 此外还要求类型中不能含有对其它实体类型的引用,并且其它类型中也不能含有对本类型引用的属性集合。一个 Complex Type 示例如下所示
public partial class OnsiteCourse : Course { public OnsiteCourse() { Details = new Details(); } public Details Details { get; set; } } public class Details { public System.DateTime Time { get; set; } public string Location { get; set; } public string Days { get; set; } }
五、移除约定(Removing Conventions)
可以移除任何定义于命名空间 System.Data.Entity.ModelConfiguration.Conventions 中的约定,如下列示例移除约定 PluralizingTableNameConvention
public class SchoolContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove(); } }
说明:本文是在学习 Entity Framework Code First Conventions 的随笔记录,对原文做了一个意译以更好地为自己所用。原文请参考 (推荐阅读)