设计器 TPH 继承Designer TPH Inheritance

此分步演练演示如何使用 Entity Framework Designer (EF 设计器) 实现概念模型中的每个层次结构一个表 (TPH) 继承。This step-by-step walkthrough shows how to implement table-per-hierarchy (TPH) inheritance in your conceptual model with the Entity Framework Designer (EF Designer). TPH 继承使用一个数据库表来维护继承层次结构中所有实体类型的数据。TPH inheritance uses one database table to maintain data for all of the entity types in an inheritance hierarchy.

在本演练中,我们会将 Person 表映射到三个实体类型: Person (基类型) 、学生 (派生自人员) ,以及人员派生的指导员 (。In this walkthrough we will map the Person table to three entity types: Person (the base type), Student (derives from Person), and Instructor (derives from Person). 我们将从数据库 () Database First 创建概念模型,然后使用 EF 设计器更改模型以实现 TPH 继承。We'll create a conceptual model from the database (Database First) and then alter the model to implement the TPH inheritance using the EF Designer.

可以使用 Model First 映射到 TPH 继承,但您必须编写自己的数据库生成工作流,该工作流非常复杂。It is possible to map to a TPH inheritance using Model First but you would have to write your own database generation workflow which is complex. 然后,将此工作流分配到 EF 设计器中的 " 数据库生成工作流 " 属性。You would then assign this workflow to the Database Generation Workflow property in the EF Designer. 更简单的替代方法是使用 Code First。An easier alternative is to use Code First.

其他继承选项Other Inheritance Options

(TPT) 的每种类型一个表是另一种类型的继承,其中,数据库中的单独表映射到参与继承的实体。Table-per-Type (TPT) is another type of inheritance in which separate tables in the database are mapped to entities that participate in the inheritance. 有关如何将每种类型一个表继承映射到 EF 设计器的信息,请参阅 Ef 设计器 TPT 继承 For information about how to map Table-per-Type inheritance with the EF Designer, see EF Designer TPT Inheritance.

实体框架运行时 (TPC) 和混合继承模型支持每个具体的表的类型继承,但 EF 设计器不支持。Table-per-Concrete Type Inheritance (TPC) and mixed inheritance models are supported by the Entity Framework runtime but are not supported by the EF Designer. 如果要使用 TPC 或混合继承,则有两个选项:使用 Code First 或手动编辑 EDMX 文件。If you want to use TPC or mixed inheritance, you have two options: use Code First, or manually edit the EDMX file. 如果选择处理 EDMX 文件,"映射详细信息" 窗口将进入 "安全模式",您将无法使用设计器来更改映射。If you choose to work with the EDMX file, the Mapping Details Window will be put into “safe mode” and you will not be able to use the designer to change the mappings.

必备条件Prerequisites

若要完成此演练,您需要:To complete this walkthrough, you will need:

设置项目Set up the Project

  • 打开 Visual Studio 2012。Open Visual Studio 2012.
  • 选择 文件- > 新建- > 项目Select File-> New -> Project
  • 在左窗格中,单击 " Visual # C",然后选择 "控制台" 模板。In the left pane, click Visual C#, and then select the Console template.
  • 输入 TPHDBFirstSample   作为名称。Enter TPHDBFirstSample as the name.
  • 选择“确定”。 ****Select OK.

创建模型Create a Model

  • 在解决方案资源管理器中右键单击项目名称,然后选择 " 添加- > 新建项"。Right-click the project name in Solution Explorer, and select Add -> New Item.
  • 从左侧菜单中选择 " 数据 ",然后在 "模板" 窗格中选择 " ADO.NET 实体数据模型Select Data from the left menu and then select ADO.NET Entity Data Model in the Templates pane.
  • 输入 TPHModel 作为文件名,然后单击 " 添加"。Enter TPHModel.edmx for the file name, and then click Add.
  • 在 "选择模型内容" 对话框中,选择 " 从数据库生成",然后单击 " 下一步"。In the Choose Model Contents dialog box, select Generate from database, and then click Next.
  • 单击 " 新建连接"。Click New Connection. 在 "连接属性" 对话框中,输入服务器名称 (例如, ** (localdb) \ mssqllocaldb**) ,选择身份验证方法,为数据库名称键入 School,然后   单击 **"确定"**。In the Connection Properties dialog box, enter the server name (for example, (localdb)\mssqllocaldb), select the authentication method, type School for the database name, and then click OK. "选择您的数据连接" 对话框将通过数据库连接设置进行更新。The Choose Your Data Connection dialog box is updated with your database connection setting.
  • 在 "选择数据库对象" 对话框中的 "表" 节点下,选择 Person 表。In the Choose Your Database Objects dialog box, under the Tables node, select the Person table.
  • 单击 " 完成"。Click Finish.

此时会显示 Entity Designer,它提供了用于编辑模型的设计图面。The Entity Designer, which provides a design surface for editing your model, is displayed. 您在 "选择数据库对象" 对话框中选择的所有对象都将添加到模型中。All the objects that you selected in the Choose Your Database Objects dialog box are added to the model.

这就是 " Person " 表在数据库中的外观。That is how the Person table looks in the database.

Person 表 

实现每个层次结构一个表继承Implement Table-per-Hierarchy Inheritance

 Person表具有鉴别器列,该列可以具有以下两个值之一: "Student" 和 "讲师"。The Person table has the Discriminator column, which can have one of two values: “Student” and “Instructor”. 根据值, Person 表将映射到 " 学生 " 实体或 " 讲师 " 实体。Depending on the value the Person table will be mapped to the Student entity or the Instructor entity.  Person表还具有两列 " 雇佣日期"   和 " EnrollmentDate",这两列必须是可以为 null的,因为用户不能同时是学生和指导员 (此演练) 。The Person table also has two columns, HireDate and EnrollmentDate, which must be nullable because a person cannot be a student and an instructor at the same time (at least not in this walkthrough).

添加新实体Add new Entities

  • 添加新实体。Add a new entity. 为此,请右键单击 Entity Framework Designer 设计图面的空白区域,然后选择 " 添加 > 实体"。To do this, right-click on an empty space of the design surface of the Entity Framework Designer, and select Add->Entity.
  • 为 Instructor   " 实体名称" 键入 "指导员   ",然后 Person   从 " 基类型" 下拉列表中选择 "人员"。Type Instructor for the Entity name and select Person from the drop-down list for the Base type.
  • 单击 "确定"Click OK.
  • 添加另一个新实体。Add another new entity. 键入 Student   "Student" 作为 " 实体名称"   ,然后从 " Person    基类型" 下拉列表中选择 "人员"。Type Student for the Entity name and select Person from the drop-down list for the Base type.

已将两个新的实体类型添加到设计图面。Two new entity types were added to the design surface. 箭头指向 " person" 实体类型的新实体类型   ; 这表示该 用户   是新实体类型的基类型。An arrow points from the new entity types to the Person entity type; this indicates that Person is the base type for the new entity types.

  • 右键单击 Person 实体的 " 雇佣日期"   属性 Person   。Right-click the HireDate property of the Person entity. 选择 " 剪切 (或使用 Ctrl-X 键) 。Select Cut (or use the Ctrl-X key).
  • 右键单击 讲师   实体,然后选择 " 粘贴 (或使用 Ctrl + V 键) 。Right-click the Instructor entity and select Paste (or use the Ctrl-V key).
  • 右键单击 " 雇佣日期"   属性,然后选择 " 属性"。Right-click the HireDate property and select Properties.
  • 在 " 属性"   窗口中,将 可为 null的   属性设置为 falseIn the Properties window, set the Nullable property to false.
  • 右键单击 Person 实体的 EnrollmentDate   属性 Person   。Right-click the EnrollmentDate property of the Person entity. 选择 " 剪切 (或使用 Ctrl-X 键) 。Select Cut (or use the Ctrl-X key).
  • 右键单击 " 学生 " 实体,然后选择 " 粘贴 (或使用 Ctrl + V 键) 。Right-click the Student entity and select Paste(or use the Ctrl-V key).
  • 选择 EnrollmentDate   属性并将 可为 null的   属性设置为 falseSelect the EnrollmentDate property and set the Nullable property to false.
  • 选择 " 人员"   实体类型。Select the Person entity type. 在 " 属性"   窗口中,将其 " 抽象" 属性设置   为 " true"。In the Properties window, set its Abstract property to true.
  • 删除Person鉴别器属性。Delete the Discriminator property from Person. 下一节将对其删除原因进行说明。The reason it should be deleted is explained in the following section.

映射实体Map the entities

  • 右键单击 讲师 ,然后选择 " 表映射"。Right-click the Instructor and select Table Mapping. 在 "映射详细信息" 窗口中选择 "指导员" 实体。The Instructor entity is selected in the Mapping Details window.

  • 在 "映射详细信息" 窗口中单击 " ** < 添加表或视图 > **   " Mapping Details   。Click <Add a Table or View> in the Mapping Details window. " ** < 添加表" 或 " > 视图**"   字段将成为所选实体可映射到的表或视图的下拉列表。The <Add a Table or View> field becomes a drop-down list of tables or views to which the selected entity can be mapped.

  •  Person   从下拉列表中选择 "人员"。Select Person from the drop-down list.

  • 映射详细信息"   窗口将更新为默认的列映射,并提供一个用于添加条件的选项。The Mapping Details window is updated with default column mappings and an option for adding a condition.

  • 单击 " ** < 添加条件 > **"。Click on <Add a Condition>. " ** < 添加条件 > **"   字段将成为可以为其设置条件的列的下拉列表。The <Add a Condition> field becomes a drop-down list of columns for which conditions can be set.

  •  Discriminator   从下拉列表中选择 "鉴别器"。Select Discriminator from the drop-down list.

  • 在 Operator   " 映射详细信息" 窗口的 "运算符" 列中   ,从下拉列表中选择 "="。In the Operator column of the Mapping Details window, select = from the drop-down list.

  • 在 " 值/属性 " 列中,键入 " 讲师"。In the Value/Property column, type Instructor. 最终结果应该如下所示:The end result should look like this:

    映射详细信息

  • 对于 " 学生"   实体类型,请重复这些步骤,但将条件设置为 "学生" 值。Repeat these steps for the Student entity type, but make the condition equal to Student value.
    删除鉴别器属性的原因是,您不能多次映射一个表列。此列将用于条件映射,因此它也不能用于属性映射。如果条件使用 **Is null*   或 is Not null比较,则可以使用这两种方法   。*The reason we wanted to remove the Discriminator property, is because you cannot map a table column more than once. This column will be used for conditional mapping, so it cannot be used for property mapping as well. The only way it can be used for both, if a condition uses an Is Null or Is Not Null comparison.

“每个层次结构一个表”继承实现完毕。Table-per-hierarchy inheritance is now implemented.

最终 TPH

使用模型Use the Model

打开 Program.cs 文件,其中定义了 Main 方法。Open the Program.cs file where the Main method is defined. 将以下代码粘贴到 Main 函数中。Paste the following code into the Main function. 此代码执行三个查询。The code executes three queries. 第一个查询返回所有 Person 对象。The first query brings back all Person objects. 第二个查询使用 OfType 方法返回 指导员 对象。The second query uses the OfType method to return Instructor objects. 第三个查询使用 OfType 方法返回 学生 对象。The third query uses the OfType method to return Student objects.

    using (var context = new SchoolEntities())
    {
        Console.WriteLine("All people:");
        foreach (var person in context.People)
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Instructors only: ");
        foreach (var person in context.People.OfType<Instructor>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Students only: ");
        foreach (var person in context.People.OfType<Student>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }
    }