Code First 约定

Code First 使你能够使用 C# 或 Visual Basic .NET 类来描述模型。 通过使用约定可以检测模型的基本形状。 约定是一组规则,用于在使用 Code First 时自动配置基于类定义的概念模型。 约定在 System.Data.Entity.ModelConfiguration.Conventions 命名空间中定义。

可以使用数据注释或 Fluent API 进一步配置模型。 通过 Fluent API 进行配置具有最高优先级,然后是数据注释和约定。 有关详细信息,请参阅数据注释Fluent API - 关系Fluent API - 类型和属性以及使用 VB.NET 的 Fluent API

API 文档中提供了 Code First 约定的详细列表。 本主题概述 Code First 使用的约定。

类型发现

使用 Code First 开发时,通常先编写定义概念(域)模型的 .NET Framework 类。 除了定义类之外,还需要让 DbContext 了解要包括在模型中的类型。 为此,请定义一个派生自 DbContext 的上下文类,并公开要包含在模型中的 DbSet 属性。 Code First 将包含这些类型,并且还会拉取任何引用的类型,即使引用的类型是在不同的程序集中定义的。

如果类型参与继承层次结构,则足以定义基类的 DbSet 属性,并且如果派生类型与基类位于同一程序集中,则会自动包含派生类型

在下面的示例中,SchoolEntities 类上只定义了一个 DbSet 属性 (Departments)。 Code First 使用此属性发现和拉取任何引用的类型。

public class SchoolEntities : DbContext
{
    public DbSet<Department> Departments { get; set; }
}

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }
    public string Name { get; set; }

    // Navigation property
    public virtual ICollection<Course> 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 属性或 DbModelBuilder.Ignore Fluent API

modelBuilder.Ignore<Department>();

主键约定

如果类上的属性名为“ID”或者类名后跟“ID”,Code First 会推断该属性是主键。 如果主键属性的类型是数字或 GUID,则它将配置为标识列。

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }

    . . .  

}

关系约定

在实体框架中,导航属性提供了一种在两个实体类型之间导航关系的方法。 针对对象参与到其中的每个关系,各对象均可以具有导航属性。 使用导航属性,可以在两个方向上导航和管理关系,在重数为一或者零或一的情况下,返回引用对象,在重数为多个的情况下,返回一个集合。 Code First 根据类型上定义的导航属性推断关系。

除了导航属性,我们还建议在表示依赖对象的类型中包括外键属性。 数据类型与主体主键属性相同且名称遵循以下格式之一的任何属性都表示关系的外键:“<navigation property name><principal primary key property name>”、“<principal class name><primary key property name>”或“<principal primary key property name>”。 如果找到多个匹配项,则按上面列出的顺序给出优先级。 外键检测不区分大小写。 检测到外键属性时,Code First 根据外键的为 Null 性推断关系的多重性。 如果属性可为空,则关系注册为可选;否则,关系将注册为必需。

如果依赖实体上的外键不可为 null,Code First 会对关系设置级联删除。 如果依赖实体上的外键可为 null,Code First 不会对关系设置级联删除,并且删除主体时,外键将设置为 null。 可以使用 Fluent API 重写约定检测到的重数和级联删除行为。

在下面的示例中,导航属性和外键用于定义 Department 类和 Course 类之间的关系。

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }
    public string Name { get; set; }

    // Navigation property
    public virtual ICollection<Course> 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; }
}

注意

如果相同类型之间具有多个关系(例如,假设定义了 Person 和 Book 类,其中 Person 类包含 ReviewedBooks 和 AuthoredBooks 导航属性,并且 Book 类包含 Author 和 Reviewer 导航属性),则需要使用数据注释或 Fluent API 手动配置关系。 有关详细信息,请参阅数据注释Fluent API - 关系

复杂类型约定

Code First 发现无法推断主键的类定义,并且没有通过数据注释或 Fluent API 注册主键时,该类型会自动注册为复杂类型。 复杂类型检测还要求该类型没有引用实体类型的属性,并且不从另一种类型的集合属性进行引用。 在提供以下类定义的情况下,Code First 会推断 Details 是复杂类型,因为它没有主键

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; }
}

连接字符串约定

若要了解 DbContext 用于发现要使用的连接的约定,请参阅连接和模型

删除约定

可以删除 System.Data.Entity.ModelConfiguration.Conventions 命名空间中定义的任何约定。 以下示例删除 PluralizingTableNameConvention

public class SchoolEntities : DbContext
{
     . . .

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure Code First to ignore PluralizingTableName convention
        // If you keep this convention, the generated tables  
        // will have pluralized names.
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

自定义约定

EF6 以上版本支持自定义约定。 有关详细信息,请参阅自定义 Code First 约定