设计器 TPH 继承Designer TPH Inheritance

此分步演练演示如何使用 Entity Framework Designer (EF 设计器)在概念模型中实现每个层次结构一个表(TPH)继承。 TPH 继承使用一个数据库表来维护继承层次结构中所有实体类型的数据。

在本演练中,我们会将 Person 表映射到三个实体类型: Person (基类型)、学生(派生自人员)和讲师(派生自人员)。 我们将从数据库(Database First)创建概念模型,然后使用 EF 设计器更改模型以实现 TPH 继承。

可以使用 Model First 映射到 TPH 继承,但您必须编写自己的数据库生成工作流,该工作流非常复杂。 然后,将此工作流分配到 EF 设计器中的 “数据库生成工作流“ 属性。 更简单的替代方法是使用 Code First。

其他继承选项Other Inheritance Options

每种类型一个表(TPT)是另一种类型的继承,其中,数据库中的单独表映射到参与继承的实体。 有关如何将每种类型一个表继承映射到 EF 设计器的信息,请参阅Ef 设计器 TPT 继承

实体框架运行时支持每个具体的表类型继承(TPC)和混合继承模型,但 EF 设计器不支持。 如果要使用 TPC 或混合继承,则有两个选项:使用 Code First 或手动编辑 EDMX 文件。 如果选择处理 EDMX 文件,”映射详细信息” 窗口将进入 “安全模式”,您将无法使用设计器来更改映射。

先决条件Prerequisites

若要完成此演练,您需要:

设置项目Set up the Project

  • 打开 Visual Studio 2012。
  • 选择 “文件->”> 项目
  • 在左窗格中,单击 “ Visual C# “,然后选择 “控制台“ 模板。
  • 输入 “ TPHDBFirstSample “ 作为名称。
  • 选择“确定”。 ****

创建模型Create a Model

  • 右键单击 “解决方案资源管理器中的项目名称,然后选择”添加-> 新项“。
  • 从左侧菜单中选择 “数据“,然后在 “模板” 窗格中选择 “ ADO.NET 实体数据模型
  • 输入TPHModel作为文件名,然后单击 “添加“。
  • 在 “选择模型内容” 对话框中,选择 “ 从数据库生成“,然后单击 “ 下一步“。
  • 单击 “ 新建连接“。 在 “连接属性” 对话框中,输入服务器名称(例如, (localdb)\mssqllocaldb),选择身份验证方法,为数据库名称键入 School ,然后单击 “确定” 。 “选择您的数据连接” 对话框将通过数据库连接设置进行更新。
  • 在 “选择数据库对象” 对话框中的 “表” 节点下,选择 Person表。
  • 单击 “ 完成“。

此时会显示 Entity Designer,它提供了用于编辑模型的设计图面。 您在 “选择数据库对象” 对话框中选择的所有对象都将添加到模型中。

这就是 “ Person “ 表在数据库中的外观。

Person 表

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

Person表具有鉴别器列,该列可以具有以下两个值之一: “Student” 和 “讲师”。 根据值, Person表将映射到 “学生“ 实体或 “讲师“ 实体。 Person表还具有两列: “ 雇佣日期” 和 “ EnrollmentDate“,这些列必须可以为null ,因为用户不能同时是学生和指导员(至少在本演练中没有)。

添加新实体Add new Entities

  • 添加新实体。 为此,请右键单击 Entity Framework Designer 设计图面的空白区域,然后选择 “ >“ 实体
  • 为 “ 实体名称“ 键入 “ 指导员 “ 然后从 “ 基类型“ 下拉列表中选择 “ 人员 “。
  • 单击 “确定”
  • 添加另一个新实体。 为 “ 实体名称“ 键入 “ Student “ 然后从 “ 基类型“ 下拉列表中选择 “ 人员 “。

已将两个新的实体类型添加到设计图面。 箭头从新的实体类型指向 实体类型的 人员;这表示 用户 是新实体类型的基类型。

  • 右键单击 人员 实体的 “ 雇佣日期” 属性。 选择 “ 剪切“ (或使用 Ctrl + X 键)。
  • 右键单击 讲师 实体,然后选择 “ 粘贴“ (或使用 Ctrl + V 键)。
  • 右键单击 “ 雇佣日期” 属性,然后选择 “ 属性“。
  • 在 “ 属性 “ 窗口中,将 “ 可以为 null的 属性设置为 false
  • 右键单击 Person 实体的 EnrollmentDate 属性。 选择 “ 剪切“ (或使用 Ctrl + X 键)。
  • 右键单击 “ 学生“ 实体,然后选择 “ 粘贴” (或使用 Ctrl + V 键)。
  • 选择 EnrollmentDate 属性,并将 可为 null的 属性设置为 false
  • 选择 “ 人员“ 实体类型。 在 “ 属性 “ 窗口中,将其 Abstract 属性设置为 true
  • 删除Person鉴别器属性。 下一节将对其删除原因进行说明。

映射实体Map the entities

  • 右键单击 讲师,然后选择 “表映射”。 在 “映射详细信息” 窗口中选择 “指导员” 实体。

  • 在 “ 映射详细信息“ 窗口中,单击 “ <添加表或视图> “。 <添加表或视图> “字段将成为所选实体可映射到的表或视图的下拉列表。

  • 从下拉列表中选择 Person

  • 映射详细信息“ “窗口使用默认列映射和一个用于添加条件的选项进行更新。

  • 单击 “ <>添加条件<”添加条件”> “字段将成为可以设置条件的列的下拉列表。

  • 从下拉列表中选择 “ 鉴别器 。

  • 在 “ 映射详细信息“ 窗口的 “ 运算符 “ 列中,从下拉列表中选择 “=”。

  • 在 “ 值/属性“ 列中,键入 “ 讲师“。 最终结果应该如下所示:

    映射详细信息

  • 为 “ 学生 “ 实体类型重复上述步骤,但将条件设置为 “学生“ 值。
    删除鉴别器属性的原因是,您不能多次映射一个表列。此列将用于条件映射,因此它也不能用于属性映射。对于这两种情况,唯一的方法是:如果条件使用 Is null 或者不 是 null 比较。

“每个层次结构一个表”继承实现完毕。

最终 TPH

使用模型Use the Model

打开Program.cs文件,其中定义了Main方法。 将以下代码粘贴到Main函数中。 此代码执行三个查询。 第一个查询返回所有Person对象。 第二个查询使用OfType方法返回指导员对象。 第三个查询使用OfType方法返回学生对象。

  1. using (var context = new SchoolEntities())
  2. {
  3. Console.WriteLine("All people:");
  4. foreach (var person in context.People)
  5. {
  6. Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
  7. }
  8. Console.WriteLine("Instructors only: ");
  9. foreach (var person in context.People.OfType<Instructor>())
  10. {
  11. Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
  12. }
  13. Console.WriteLine("Students only: ");
  14. foreach (var person in context.People.OfType<Student>())
  15. {
  16. Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
  17. }
  18. }