本主题介绍如何通过修改实体数据模型 (EDM) 中的概念模型实现每种类型一个表继承。每种类型一个表继承使用数据库中单独的表为继承层次结构中的每种类型维护非继承属性和键属性的数据。有关使用 EDM 实现继承的更多信息,请参见继承 (EDM)。
本演练将通过修改 CourseManager 应用程序使用的 EDM 来实现每种类型一个表继承(有关更多信息,请参见本主题后面的“前提条件”一节。)
在 CourseManager 应用程序中,Course、OnlineCourse 和 OnsiteCourse 实体类型映射到相应的同名表。因为 OnlineCourse 和 OnsiteCourse 实体类型包含两种课程类型特有的信息且共享一个公共键,所以可将这两种实体类型更改为从 Course 实体类型继承。下面的步骤总结了在此示例中如何实现每种类型一个表继承(本主题后面提供了更详细的步骤):
- 删除 OnlineCourse 实体类型和 Course 实体类型间的关联。删除 OnsiteCourse 实体类型和 Course 实体类型间的关联。这些关联将通过实现继承层次结构被替换。 
- 从 OnlineCourse 和 OnsiteCourse 实体类型删除 CourseID 键属性。此属性将从 Course 实体类型继承。 
- 将 Course 实体类型设置为 OnlineCourse 和 OnsiteCourse 实体类型的基类型。 
- 将 Course 实体类型设置为抽象类型。 
- 将 OnlineCourse 和 OnsiteCourse 实体类型的继承的 CourseID 属性映射到相应的列。 
系统必备
要完成本演练,必须生成 CourseManager 应用程序。有关更多信息和说明,请参见实体框架快速入门。将通过实现每种类型一个表继承修改 CourseManager 应用程序中使用的 EDM。然后将扩展该应用程序的功能以分开显示选中部门的在线课程和现场课程。
| .gif) 注意 | 
|---|
| 因为本文档中的许多演练主题都使用该 CourseManager 应用程序作为起点,所以建议在本演练中使用 CourseManager 应用程序的副本,而不要编辑原始 CourseManager 代码。 | 
此演练假定读者了解 Visual Studio 和 .NET Framework 的基本知识并拥有使用 Visual C# 或 Visual Basic 进行编程的基本能力。
实现每种类型一个表继承
在此过程中,将更改 SchoolModel EDM 的概念性部分以实现每种类型一个表继承。
实现每种类型一个表继承
- 在 Visual Studio 中打开 CourseManager 解决方案。 
- 在解决方案资源管理器中,双击 School.edmx 文件。 - 这将在实体数据模型设计器(实体设计器)中打开 School.edmx 文件。 
- 右键单击 OnlineCourse 实体类型并选择**“属性”**。 
- 在**“属性”窗口中,将“基类型”**属性设置为 Course。 
- 为 OnsiteCourse 实体类型重复步骤 3 和 4。 
- 右键单击 OnlineCourse 和 Course 实体类型之间的关联(线)。选择**“删除”**。 
- 右键单击 OnsiteCourse 和 Course 实体类型之间的关联。选择**“删除”**。 
- 右键单击 OnlineCourse 实体类型的 CourseID 属性,然后选择**“删除”**。 
- 右键单击 OnsiteCourse 实体类型的 CourseID 属性,然后选择**“删除”**。 
- 选择 Course 实体类型。在**“属性”窗口中将其“抽象”**属性设置为 true。 - 出现一个消息框,称将某个实体类型定义为抽象类型将会移除此类型现有的所有函数映射。单击**“确定”**。 .gif) 注意 注意- 由于已将 Course 实体类型更改为抽象类型,原始 CourseManager 应用程序的更新功能将失效。 
- 右键单击 OnlineCourse 实体类型并选择**“表映射”**。 - 将出现**“映射详细信息”**窗口。 
- 单击对应于 CourseID 列的**“值/属性”**字段。 - **“值/属性”**字段变为一个下拉列表,其中包含可映射到相应列的属性。 
- 从下拉列表中选择 CourseID。 
- 为 OnsiteCourse 实体类型重复步骤 11 到 13。 
至此已实现每种类型一个表继承。
构造用户界面
接下来,将向 CourseViewer 窗体添加一个用于加载和显示 CourseDiscrimForm 窗体的按钮。然后,添加两个 DataGridView 控件用于显示 OnsiteCourses 和 OnlineCourses。最后将 DataGridView 绑定到 BindingSource 控件。有关将对象绑定到控件的更多信息,请参见将对象绑定到控件(实体框架)。
构造用户界面
- 在**“解决方案资源管理器”中右键单击 CourseManager 项目,指向“添加”,然后选择“新建项”**。 - 出现**“添加新项”**对话框。 
- 选择**“Windows 窗体”然后单击“添加”**。 - 新窗体即被添加到项目中,并在窗体设计器中打开。 
- 在**“属性”**窗口中,将窗体的名称设置为 CourseDiscriminator。 - 新窗体即被添加到项目中,并在窗体设计器中打开。该窗体的名称设置为 CourseDiscriminator,文本设置为 CourseDiscriminator。 
- 从工具箱将 ComboBox 控件拖入此窗体,然后在**“属性”**窗口中将其名称设置为 departmentList。 
- 从工具箱将 DataGridView 控件拖动到窗体上,并将其名称设置为 onsiteGridView。 
- 再从工具箱将另一个 DataGridView 控件拖动到窗体上,并将其名称设置为 onlineGridView。 
- 在**“解决方案资源管理器”**中,双击 CourseViewer.cs 或 CourseViewer.vb。 - 出现 CourseViewer 窗体的设计视图。 
- 从工具箱将 Button 控件拖入 CourseViewer 窗体。 
- 在**“属性”**窗口,中将 Button 的名称设置为 viewDiscriminator 并将该按钮的文本设置为 Online vs. Onsite。 
- 双击 viewDiscriminatorButton。 - 将打开窗体的代码隐藏文件。 
- 将下面的代码添加到 viewDiscriminator_click 事件处理程序中: - Dim courseDiscrim As New CourseDiscriminator courseDiscrim.Visible = True- CourseDiscriminator courseDiscrim = new CourseDiscriminator(); courseDiscrim.Visible = true;
现在,就完成了此窗体的用户界面。
查询 EDM
此过程将查询 EDM 并将结果绑定到 Windows 窗体控件。
查询 EDM
- 在窗体设计器中打开 CourseDiscriminator 窗体。 
- 从工具箱将 BindingSource 控件拖入此窗体。 
- 在**“属性”**窗口中,将 BindingSource 的名称设置为 onsiteBindingSource。 
- 在**“属性”窗口中单击“DataSource”**属性旁边的字段。 - 该字段将变成包含可用数据源的下拉列表。 
- 单击**“添加项目数据源”**。 - 将打开**“数据源配置向导”的“选择数据源类型”**窗口。 
- 在**“应用程序从哪里获取数据?”框中,选择“对象”**。 
- 单击**“下一步”**。 - 将打开**“选择希望绑定到的对象”**窗口。该窗口中显示可用资源树的顶端节点。 
- 展开 CourseManager 节点,然后展开 SchoolModel (C#) 或 CourseManager.SchoolModel (Visual Basic) 节点。 
- 选择 OnsiteCourse 并单击**“完成”**。 
- 重复步骤 2 到 9,但将 BindingSource 控件命名为 OnlineBindingSource 并将其绑定到 OnlineCourse 对象。 
- 右键单击 OnsiteGridView 控件并选择**“属性”**。 
- 在**“属性”**窗口中,单击 DataSource 属性旁边的字段。 - 该字段将变成包含可用数据源的下拉列表。 
- 选择 OnsiteBindingSource 
- 为 OnlineGridView 重复步骤 11 到 13,但将**“DataSouce”**属性设置为 OnlineBindingSource。 .gif) 注意 注意- OfType 方法返回一个枚举,DataGridView 控件无法在运行时从此枚举生成列。为了在此示例中显示所需的信息,在设计时根据要绑定到的类通过 BindingSource 控件为 DataGridView 控件设置了数据源。 
- 双击 CourseDiscriminator 窗体。 - CourseDiscriminator 窗体的代码隐藏文件打开。 
- 添加以下 using (C#) 或 Imports (Visual Basic) 语句,以引用基于 School 数据库和实体命名空间创建的模型。 - Imports System.Data.Objects Imports System.Data.Objects.DataClasses- using System.Data.Objects; using System.Data.Objects.DataClasses;
- 将表示数据上下文的属性添加到 CourseDiscriminator 类中: - ' Create an ObjectContext instance based on SchoolEntity. Private schoolContext As SchoolEntities- // Create an ObjectContext instance based on SchoolEntity. private SchoolEntities schoolContext;
- 在 CourseDiscriminator_Load 事件处理程序中,添加代码以初始化对象上下文并将 departmentList 控件绑定到返回 Department 信息的查询。 - ' 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. departmentList.DataSource = departmentQuery _ .Execute(MergeOption.OverwriteChanges) 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";
- 返回 CourseDiscriminator 窗体的设计器视图,然后双击 departmentListComboBox 控件。 - 将打开代码隐藏文件。departmentList_SelectedIndexChanged 事件处理程序已添加到代码中。 
- 向 departmentList_SelectedIndexChanged 事件处理程序添加以下代码以更新 BindingSource 控件的数据源。 - ' Get the selected department object. Dim department As Department = CType(Me.departmentList. _ SelectedItem, Department) ' Update the data sources for the BindingSource controls. onsiteBindingSource.DataSource = department.Course _ .OfType(Of OnsiteCourse)() onlineBindingSource.DataSource = department.Course _ .OfType(Of OnlineCourse)()- // Get the selected department object. Department department = (Department)this.departmentList .SelectedItem; // Update the data sources for the BindingSource controls. onsiteBindingSource.DataSource = department.Course .OfType<OnsiteCourse>(); onlineBindingSource.DataSource = department.Course .OfType<OnlineCourse>();
现在,就完成了应用程序。按 Ctrl+F5 运行应用程序。单击 Onsite vs. Online 按钮加载 CourseDiscriminator 窗体。选中部门的 OnsiteCourses 和 OnlineCourses 将显示在 DataGridView 控件中。
代码清单
本节列出了 CourseDiscriminator 窗体的代码隐藏文件的最终版本。
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Public Class CourseDiscriminator
    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    Private Sub CourseDiscriminator_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.
        departmentList.DataSource = departmentQuery _
        .Execute(MergeOption.OverwriteChanges)
        departmentList.DisplayMember = "Name"
    End Sub
    Private Sub departmentList_SelectedIndexChanged(ByVal sender As  _
        System.Object, ByVal e As System.EventArgs) Handles _
        departmentList.SelectedIndexChanged
        ' Get the selected department object.
        Dim department As Department = CType(Me.departmentList. _
                SelectedItem, Department)
        ' Update the data sources for the BindingSource controls.
        onsiteBindingSource.DataSource = department.Course _
            .OfType(Of OnsiteCourse)()
        onlineBindingSource.DataSource = department.Course _
            .OfType(Of OnlineCourse)()
    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 CourseDiscriminator : Form
    {
        // Create an ObjectContext instance based on SchoolEntity.
        private SchoolEntities schoolContext;
        public CourseDiscriminator()
        {
            InitializeComponent();
        }
        private void CourseDiscriminator_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 selected department object.
            Department department = (Department)this.departmentList
                .SelectedItem;
            // Update the data sources for the BindingSource controls.
            onsiteBindingSource.DataSource = department.Course
                .OfType<OnsiteCourse>();
            onlineBindingSource.DataSource = department.Course
                .OfType<OnlineCourse>();
        }
    }
}
后续步骤
您已在 EDM 中成功实现每种类型一个表继承。有关如何定义具有每种类型一个表继承的 EDM 的更多信息,请参见如何:通过每种类型一个表继承以定义模型(实体框架)。有关如何生成使用实体框架的应用程序的更多信息,请参见编程指南(实体框架)。