逐步解說:對應每個階層的資料表繼承
本主題示範如何在 Entity Data Model (EDM) 中更改概念模型以實作每個階層的資料表繼承。每個階層的資料表繼承都會使用一個資料庫資料表,以維護繼承階層架構 (Inheritance Hierarchy) 中所有實體類型的資料。如需以 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 應用程式。如需詳細資訊和指示,請參閱 Entity Framework 快速入門。在建置此應用程式之後,您必須實作每個階層的資料表繼承,藉以修改其 EDM。然後,您就可以擴充應用程式的功能,以便顯示所選課程的註冊。
附註 |
---|
因為本說明文件的許多逐步解說主題都從使用 CourseManager 應用程式開始,我們建議您為本逐步解說使用 CourseManager 應用程式的複本,而非編輯原始的 CourseManager 程式碼。 |
本逐步解說假設讀者具備以下基本能力:Visual Studio 和 .NET Framework 的使用能力,以及 Visual C# 或 Visual Basic 程式設計的能力。
實作每個階層的資料表繼承
在這個程序中,您將修改 SchoolModel EDM 的概念部分,以實作每個階層的資料表繼承。
若要實作每個階層的資料表繼承
在 Visual Studio 中開啟 CourseManager 方案。
按兩下 [方案總管] 中的 School.edmx 檔案。
School.edmx 檔案隨即在 ADO.NET 實體資料模型設計工具 (Entity Designer) 中開啟。
以滑鼠右鍵按一下 Entity Designer 設計介面的空白空間,然後指向 [加入],再按一下 [實體]。
[新增實體] 對話方塊隨即出現。
為 [實體名稱] 輸入 Instructor,然後從 [基底類型] 的下拉式清單中選取 Person。
按一下 [確定]。
在設計介面上便會建立並顯示新的實體類型。
重複步驟 3 到 5,但是在第二個步驟中為 [實體名稱] 輸入 Student。
現在,您在設計介面上就有兩個已顯示的實體類型,Instructor 和 Student。箭頭由新實體類型指向 Person 實體類型,這表示 Person 是新實體類型的基底類型。
以滑鼠右鍵按一下 Person 實體類型的 [HireDate] 屬性 (在 [純量屬性] 下方),然後選取 [剪下]。
以滑鼠右鍵按一下 Instructor 實體類型的 [純量屬性] 屬性,然後選取 [貼上]。
以滑鼠右鍵按一下 [HireDate] 屬性,然後選取 [屬性]。
在 [屬性] 視窗中將 [Nullable] 屬性設為 false。
重複步驟 7 到 10,但是剪下 Person 實體類型的 [EnrollmentDate] 屬性,並將它貼至 Student 實體類型。
選取 Person 實體類型。在 [屬性] 視窗中將它的 [Abstract] 屬性設為 true。
隨即會出現一個訊息方塊,告知您定義實體類型為抽象將會移除那個類型的所有現有函式對應。按一下 [確定]。
附註 一般來說,您不必使用抽象型別來塑模每個階層的資料表繼承案例。本範例的抽象型別是用來示範其在 EDM 中的用法。
附註 本程序的剩餘步驟需要用到 [對應詳細資料] 視窗。如果沒有顯示這個視窗,請以滑鼠右鍵按一下設計介面,然後選取 [對應詳細資料]。
選取 Instructor 實體類型,然後按一下 [對應詳細資料] 視窗中的 [<加入資料表或檢視>]。
[<加入資料表或檢視>] 欄位會變成所選實體可對應之資料表或檢視表的下拉式清單。
從下拉式清單中選取 Person。
[對應詳細資料] 視窗會更新成預設資料行對應和用於加入條件的選項。
按一下 [<加入函式>]。
[<加入函式>] 欄位會變成可設定條件之資料行的下拉式清單。
從下拉式清單中選取 HireDate。
另一個 [<加入函式>] 欄位隨即出現。
在 [對應詳細資料] 視窗的 [運算子] 資料行中,從下拉式清單中選取 [Is]。
在 [屬性/值] 資料行中選取 [Not Null]。
按一下 [<加入函式>]。
從下拉式清單中選取 EnrollmentDate。
在 [運算子] 資料行中,從下拉式清單中選取 [Is]。
在 [屬性/值] 資料行中選取 [Null]。
附註 如果在條件中使用值/屬性,則除非條件使用 [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 Form],然後將表單的名稱設為 Enrollment.vb 或 Enrollment.cs (視使用的語言而定),再按一下 [加入]。
新的表單隨即加入至專案並在表單設計工具中開啟。這個表單的名稱已設為 Enrollment,而且文字已設為 Enrollment。
將 ComboBox 控制項從 [工具箱] 拖曳至表單,並在 [屬性] 視窗中將它的名稱設為 departmentList。
將另一個 ComboBox 控制項從 [工具箱] 拖曳至表單,並將它的名稱設為 courseList。
將 Listbox 控制項從 [工具箱] 拖曳至表單。在 [屬性] 視窗中將它的名稱設為 studentList。
按兩下 [方案總管] 中的 CourseViewer.cs 或 CourseViewer.vb。
CourseViewer 表單的設計檢視隨即出現。
將 Button 控制項從 [工具箱] 拖曳至 CourseViewer 表單。
在 [屬性] 視窗中將按鈕的名稱設為 viewEnrollment,然後將按鈕的文字設為 View Enrollment。
按兩下 [viewEnrollment] 按鈕。
CourseViewer 表單之程式碼後置(Code-Behind) 的檔案隨即開啟。
將下列程式碼加入至 viewEnrollment_click 事件處理常式:
Dim enrollmentForm As New Enrollment() enrollmentForm.Visible = True
Enrollment enrollmentForm = new Enrollment(); enrollmentForm.Visible = true;
現已完成使用者介面。
查詢 EDM
在這個程序中,您將查詢 EDM,並將結果繫結至 Windows Form 控制項。如需將物件繫結至控制項的詳細資訊,請參閱將物件與控制項繫結 (Entity Framework)。
若要查詢 EDM
表單設計工具中已開啟 Enrollment 表單時,按兩下 Enrollment 表單。
Enrollment 表單之程式碼後置的檔案隨即開啟。
加入下列 using (C#) 或 Imports (Visual Basic) 陳述式,以便參考 EDM 命名空間 (Namespace):
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 的詳細資訊,請參閱 HOW TO:使用每個階層的資料表繼承來定義模型 (Entity Framework)。如需如何使用 Entity Framework 建置應用程式的詳細資訊,請參閱程式設計指南 (Entity Framework)。