本主题介绍如何通过修改实体数据模型 (EDM) 中的概念模型,而实现“每个层次结构一个表”继承。“每个层次结构一个表”继承使用数据库表维护继承层次结构中的所有实体类型的数据。有关使用 EDM 实现继承的更多信息,请参见继承 (EDM)。
本演练将通过修改 CourseManager 应用程序中使用的 EDM 而实现“每个层次结构一个表”继承(有关更多信息,请参见本主题后面的“系统必备”一节。)
在 CourseManager EDM 中,Person 实体类型有两个属性:HireDate 和 EnrollmentDate,二者可属于从 Person 继承的新实体类型(分别是 Instructor 和 Student)。以下步骤概述了在本例中如何实现“每个层次结构一个表”继承。本演练中的过程将提供更多详细信息。
- 创建两个新实体类型:Instructor 和 Student。 
- 将每个新实体类型的基类型设置为 Person。 
- 将 HireDate 属性从 Person 移到 Instructor,并将 EnrollmentDate 属性从 Person 移到 Student。 
- 将 Person 实体类型设置为抽象类型。 
- 按照以下两个条件将 Instructor 实体类型映射到 Person 表:HireDate Is Not Null 和 EnrollmentDate Is Null。 
- 按照以下两个条件将 Student 实体类型映射到 Person 表:EnrollmentDate Is Not Null 和 HireDate Is Null。 
系统必备
要完成本演练,必须生成 CourseManager 应用程序。有关更多信息和说明,请参见实体框架快速入门。生成此应用程序之后,您将通过实现“每个层次结构一个表”继承而修改此应用程序的 EDM。然后,您将扩展此应用程序的功能,以显示选定课程的注册情况。
| .gif) 注意 | 
|---|
| 因为本文档中的许多演练主题都使用该 CourseManager 应用程序作为起点,所以建议在本演练中使用 CourseManager 应用程序的副本,而不要编辑原始 CourseManager 代码。 | 
本演练假定读者具备 Visual Studio、.NET Framework 的基本知识,并能使用 Visual C# 或 Visual Basic 进行编程。
实现“每个层次结构一个表”继承
下面的过程将更改 SchoolModel EDM 的概念部分以实现“每个层次结构一个表”继承。
实现“每个层次结构一个表”继承
- 在 Visual Studio 中打开 CourseManager 解决方案。 
- 在解决方案资源管理器中,双击 School.edmx 文件。 - 该 School.edmx 文件将在 ADO.NET 实体数据模型设计器(实体设计器)中打开。 
- 右键单击实体设计器设计图面的空白区域,指向**“添加”,然后单击“实体”**。 - 出现**“新建实体”**对话框。 
- 对于**“实体名称”请键入 Instructor,然后从“基类型”**下拉列表中选择 Person。 
- 单击**“确定”**。 - 新的实体类型创建完毕,并且显示在设计图面上。 
- 重复步骤 3 到 5,但是在第 2 步中,对于**“实体名称”**请键入 Student。 - 现在,在设计图面上显示有两个新的实体类型:Instructor 和 Student。箭头从新的实体类型指向 Person 实体类型;这表示 Person 是新实体类型的基类型。 
- 右键单击 Person 实体类型的 HireDate 属性(在**“标量属性”下面)。选择“剪切”**。 
- 右键单击 Instructor 实体类型的**“标量属性”,然后选择“粘帖”**。 
- 右键单击 HireDate 属性,然后选择**“属性”**。 
- 在**“属性”窗口中,将“可以为 Null”**属性设置为 false。 
- 重复步骤 7 到 10,但须剪切 Person 实体类型的 EnrollmentDate 属性,并将之粘帖到 Student 实体类型中。 
- 选择 Person 实体类型。在**“属性”窗口中,将其“抽象”**属性设置为 true。 - 出现一个消息框,称将某个实体类型定义为抽象类型将会移除此类型现有的所有函数映射。单击**“确定”**。 .gif) 注意 注意- 通常,不必使用抽象类型为“每个层次结构一个表”方案建模。抽象类型在本例中用于演示它们在 EDM 中的用法。 .gif) 注意 注意- 本过程中的其余步骤要求使用“映射详细信息”窗口。如果没有显示此窗口,请右键单击设计图面,然后选择“映射详细信息”。 
- 选择 Instructor 实体类型,然后单击**“映射详细信息”窗口中的“<添加表或视图>”**。 - **“<添加表或视图>”**字段变成下拉列表,其中包含选定实体可映射到的表或视图。 
- 从下拉列表中选择 Person。 - **“映射详细信息”**窗口将会根据默认列映射以及一个关于添加条件的选项而进行更新。 
- 单击**“<添加条件>”**。 - **“<添加条件>”**字段变成一个包含列的下拉列表(可为其中各列设置条件)。 
- 从下拉列表中选择 HireDate。 - 出现另一个**“<添加条件>”**字段。 
- 在**“映射详细信息”窗口的“运算符”列中,从下拉列表中选择“Is”**。 
- 在**“属性/值”列中,选择“Not Null”**。 
- 单击**“<添加条件>”**。 
- 从下拉列表中选择 EnrollmentDate。 
- 在**“运算符”列中,从下拉列表中选择“Is”**。 
- 在**“属性/值”列中,选择“Null”**。 .gif) 注意 注意- 如果某个值/属性在某个条件中使用,那么此值/属性不能也是实体属性,除非该条件使用“Is Null”或“Is Not Null”比较。 
- 对于 Student 实体类型请重复步骤 13 到 22,但须将条件设为 HireDate Is Null 和 EnrollmentDate Is Not Null。 
“每个层次结构一个表”继承实现完毕。
构造用户界面
接下来,将向 CourseViewer 窗体添加一个用于加载和显示 Enrollment 窗体的按钮。然后,将两个 ComboBox 控件和一个 ListBox 控件添加到 Enrollment 窗体中。使用第一个 ComboBox 可以选择系。使用第二个 ComboBox 可以根据在第一个 ComboBox 中选择的系而选择课程。关于选定课程的学生和教师的列表将会显示在 ListBox 控件中。
构造用户界面
- 在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。 - 出现**“添加新项”**对话框。 
- 选择**“Windows 窗体”,将窗体的名称设置为 Enrollment.vb 或 Enrollment.cs(取决于您所使用的语言),然后单击“添加”**。 - 新窗体即被添加到项目中,并在窗体设计器中打开。该窗体的名称设置为 Enrollment,文本设置为 Enrollment。 
- 从工具箱将 ComboBox 控件拖入此窗体,然后在**“属性”**窗口中将其名称设置为 departmentList。 
- 将另外一个 ComboBox 控件拖入此窗体,然后将其名称设置为 courseList。 
- 从工具箱将 Listbox 控件拖入此窗体。在**“属性”**窗口中将其名称设置为 studentList。 
- 在**“解决方案资源管理器”**中,双击 CourseViewer.cs 或 CourseViewer.vb。 - 出现 CourseViewer 窗体的设计视图。 
- 从工具箱将 Button 控件拖入 CourseViewer 窗体。 
- 在**“属性”**窗口中,将按钮的名称设置为 viewEnrollment,然后将按钮的文本设置为 View Enrollment。 
- 双击 viewEnrollment 按钮。 - 此时将打开 CourseViewer 窗体的代码隐藏文件。 
- 将下面的代码添加到 viewEnrollment_click 事件处理程序中: - Dim enrollmentForm As New Enrollment() enrollmentForm.Visible = True- Enrollment enrollmentForm = new Enrollment(); enrollmentForm.Visible = true;
现在,就完成了用户界面。
查询 EDM
此过程将查询 EDM 并将结果绑定到 Windows 窗体控件。有关将对象绑定到控件的更多信息,请参见将对象绑定到控件(实体框架)。
查询 EDM
- 在窗体设计器中打开 Enrollment 窗体,双击 Enrollment 窗体。 - Enrollment 窗体的代码隐藏文件打开。 
- 添加下面的 using (C#) 或 Imports (Visual Basic) 语句以引用 EDM 命名空间。 - Imports System.Data.Objects Imports System.Data.Objects.DataClasses- using System.Data.Objects; using System.Data.Objects.DataClasses;
- 将表示数据上下文的属性添加到 Enrollment 类中: - ' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities- // Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
- 在 Enrollment_Load 事件处理程序中,添加相应的代码以初始化对象上下文,并将 ComboBox 控件绑定到返回所有系和相关课程信息的查询。 - ' Initialize the ObjectContext. schoolContext = New SchoolEntities() ' Define a query that returns all Department objects and ' related Course objects, ordered by name. Dim departmentQuery As ObjectQuery(Of Department) = _ schoolContext.Department.Include("Course") _ .OrderBy("it.Name") ' Bind the ComboBox control to the query, which is ' executed during data binding. Me.departmentList.DataSource = departmentQuery _ .Execute(MergeOption.OverwriteChanges) Me.departmentList.DisplayMember = "Name"- // Initialize the ObjectContext. schoolContext = new SchoolEntities(); // Define a query that returns all Department objects // and related Course objects, ordered by name. ObjectQuery<Department> departmentQuery = schoolContext.Department.Include("Course") .OrderBy("it.Name"); // Bind the ComboBox control to the query, which is // executed during data binding. this.departmentList.DataSource = departmentQuery .Execute(MergeOption.OverwriteChanges); this.departmentList.DisplayMember = "Name";
- 返回 Enrollment 窗体的设计视图,然后双击 departmentListComboBox 控件。 - departmentList_SelectedIndexChanged 事件处理程序在代码隐藏文件中创建。 
- 将相应代码添加到事件处理程序,以将 courseListComboBox 控件绑定到选定 Department 的 Course 属性 - ' Get the object for the selected department Dim department As Department = CType(Me.departmentList _ .SelectedItem, Department) ' Bind the ComboBox control Course properties of ' the selected Department. courseList.DataSource = department.Course courseList.DisplayMember = "Title"- // Get the object for the selected department. Department department = (Department)this.departmentList.SelectedItem; // Bind the ComboBox control Course properties of // the selected Department. courseList.DataSource = department.Course; courseList.DisplayMember = "Title";
- 返回 Enrollment 窗体的设计视图,然后双击 courseListComboBox 控件。 - courseList_SelectedIndexChanged 事件处理程序在代码隐藏文件中创建。 
- 将相应代码添加到事件处理程序,以在 ListBox 中显示学生列表。 - Me.studentList.Items.Clear() ' Get the CourseID from the selected Course. Dim course As Course = CType(Me.courseList.SelectedItem, _ Course) Dim courseId As Integer = course.CourseID ' Get all CourseGrade objects for the supplied CourseID Dim studentQuery As Course = schoolContext.Course.Where _ ("it.CourseID = @courseID", New ObjectParameter _ ("courseID", courseId)).Include("CourseGrade"). _ FirstOrDefault() ' Get all students for each CourseGrade For Each cg As CourseGrade In studentQuery.CourseGrade cg.PersonReference.Load() studentList.Items.Add(cg.Person.LastName + ", " + _ cg.Person.FirstName) Next studentList.Items.Add(" ") ' Get all Instructor types for the supplied CourseID Dim instructorQuery As Course = schoolContext.Course. _ Where("it.CourseID = @courseID", New ObjectParameter _ ("courseID", courseId)).Include("Person") _ .FirstOrDefault() ' Display each instructor for the specified Course For Each Instructor As Instructor In instructorQuery.Person Me.studentList.Items.Add("Instructor: " + Instructor. _ LastName + ", " + Instructor.FirstName) Next- studentList.Items.Clear(); // Get the CourseID from the selected Course. Course course = (Course)courseList.SelectedItem; int courseId = course.CourseID; // Get all CourseGrade types for the supplied CourseID Course studentQuery = schoolContext.Course.Where( "it.CourseID = @courseID", new ObjectParameter ("courseID", courseId)).Include("CourseGrade"). FirstOrDefault(); // Get all students for each CourseGrade foreach (CourseGrade cg in studentQuery.CourseGrade) { cg.PersonReference.Load(); studentList.Items.Add(cg.Person.LastName + ", " + cg.Person.FirstName); } studentList.Items.Add(" "); // Get all Instructor types for the supplied CourseID Course instructorQuery = schoolContext.Course.Where( "it.CourseID = @courseID", new ObjectParameter ("courseID", courseId)).Include("Person"). FirstOrDefault(); // Display each instructor for the specified course. foreach (Instructor instructor in instructorQuery.Person. OfType<Instructor>()) { studentList.Items.Add("Instructor: " + instructor. LastName + ", " + instructor.FirstName); }
现在,就完成了应用程序。按 Ctrl+F5 运行应用程序。单击 View Enrollment 按钮以加载 Enrollment 窗体。选定课程的课程注册情况和教师显示在 ListBox 中。
代码清单
本节列出了 Enrollment 窗体的代码隐藏文件的最终版本。
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class Enrollment
    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    Private Sub Enrollment_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()
        ' Define a query that returns all Department objects and 
        ' related Course objects, ordered by name.
        Dim departmentQuery As ObjectQuery(Of Department) = _
            schoolContext.Department.Include("Course") _
            .OrderBy("it.Name")
        ' Bind the ComboBox control to the query, which is 
        ' executed during data binding.
        Me.departmentList.DataSource = departmentQuery _
        .Execute(MergeOption.OverwriteChanges)
        Me.departmentList.DisplayMember = "Name"
    End Sub
    Private Sub departmentList_SelectedIndexChanged(ByVal sender _
            As System.Object, ByVal e As System.EventArgs) Handles _
            departmentList.SelectedIndexChanged
        ' Get the object for the selected department
        Dim department As Department = CType(Me.departmentList _
                .SelectedItem, Department)
        ' Bind the ComboBox control Course properties of
        ' the selected Department.
        courseList.DataSource = department.Course
        courseList.DisplayMember = "Title"
    End Sub
    Private Sub courseList_SelectedIndexChanged(ByVal sender As  _
            System.Object, ByVal e As System.EventArgs) Handles _
            courseList.SelectedIndexChanged
        Me.studentList.Items.Clear()
        ' Get the CourseID from the selected Course.
        Dim course As Course = CType(Me.courseList.SelectedItem,  _
             Course)
        Dim courseId As Integer = course.CourseID
        ' Get all CourseGrade objects for the supplied CourseID
        Dim studentQuery As Course = schoolContext.Course.Where _
             ("it.CourseID = @courseID", New ObjectParameter _
              ("courseID", courseId)).Include("CourseGrade"). _
              FirstOrDefault()
        ' Get all students for each CourseGrade
        For Each cg As CourseGrade In studentQuery.CourseGrade
            cg.PersonReference.Load()
            studentList.Items.Add(cg.Person.LastName + ", " + _
                                cg.Person.FirstName)
        Next
        studentList.Items.Add(" ")
        ' Get all Instructor types for the supplied CourseID
        Dim instructorQuery As Course = schoolContext.Course. _
             Where("it.CourseID = @courseID", New ObjectParameter _
                   ("courseID", courseId)).Include("Person") _
                   .FirstOrDefault()
        ' Display each instructor for the specified Course
        For Each Instructor As Instructor In instructorQuery.Person
            Me.studentList.Items.Add("Instructor: " + Instructor. _
                            LastName + ", " + Instructor.FirstName)
        Next
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
namespace CourseManager
{
    public partial class Enrollment : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;
        public Enrollment()
        {
            InitializeComponent();
        }
        private void Enrollment_Load(object sender, EventArgs e)
        {
            // Initialize the ObjectContext.
            schoolContext = new SchoolEntities();
            // Define a query that returns all Department objects
            // and related Course objects, ordered by name.
            ObjectQuery<Department> departmentQuery =
                schoolContext.Department.Include("Course")
                                        .OrderBy("it.Name");
            // Bind the ComboBox control to the query, which is
            // executed during data binding.
            this.departmentList.DataSource = departmentQuery
        .Execute(MergeOption.OverwriteChanges);
            this.departmentList.DisplayMember = "Name";
        }
        private void departmentList_SelectedIndexChanged(object sender, 
            EventArgs e)
        {
            // Get the object for the selected department.
            Department department =
                    (Department)this.departmentList.SelectedItem;
            // Bind the ComboBox control Course properties of 
            // the selected Department.
            courseList.DataSource = department.Course;
            courseList.DisplayMember = "Title";
        }
        private void courseList_SelectedIndexChanged(object sender, 
            EventArgs e)
        {
            studentList.Items.Clear();
            // Get the CourseID from the selected Course.
            Course course = (Course)courseList.SelectedItem;
            int courseId = course.CourseID;
            // Get all CourseGrade types for the supplied CourseID
            Course studentQuery = schoolContext.Course.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("CourseGrade").
                    FirstOrDefault();
            // Get all students for each CourseGrade
            foreach (CourseGrade cg in studentQuery.CourseGrade)
            {
                cg.PersonReference.Load();
                studentList.Items.Add(cg.Person.LastName + ", " +
                    cg.Person.FirstName);
            }
            studentList.Items.Add(" ");
            // Get all Instructor types for the supplied CourseID
            Course instructorQuery = schoolContext.Course.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("Person").
                    FirstOrDefault();
            // Display each instructor for the specified course.
            foreach (Instructor instructor in instructorQuery.Person.
                OfType<Instructor>())
            {
                studentList.Items.Add("Instructor: " + instructor.
                    LastName + ", " + instructor.FirstName);
            }
        } 
    }
}
后续步骤
您已在 EDM 中成功实现“每个层次结构一个表”继承。有关如何定义具有“每个层次结构一个表”继承的 EDM 的更多信息,请参见如何:通过每个层次结构一个表继承以定义模型(实体框架)。有关如何生成具有实体框架的应用程序的更多信息,请参见编程指南(实体框架)。