消費者入門 Entity Framework 4.0 Database First 和 ASP.NET 4 Web Form - 第 6 部分
By Tom Dykstra
Contoso University 範例 Web 應用程式示範如何使用 Entity Framework 4.0 和 Visual Studio 2010 建立 ASP.NET Web Forms應用程式。 如需教學課程系列的相關資訊,請參閱 系列中的第一個教學課程
實作每個階層的資料表繼承
在上一個教學課程中,您已藉由新增和刪除關聯性,以及新增與現有實體有關聯性的新實體,來處理相關資料。 本教學課程將示範如何在資料模型中實作繼承。
在物件導向程式設計中,您可以使用繼承,更輕鬆地處理相關的類別。 例如,您可以建立 Instructor
衍生自基類的 Person
和 Student
類別。 您可以在 Entity Framework 中的實體之間建立相同種類的繼承結構。
在本教學課程的這個部分中,您將不會建立任何新的網頁。 相反地,您會將衍生實體新增至資料模型,並修改現有的頁面以使用新的實體。
資料表個別階層與資料表個別類型繼承
資料庫可以將相關物件的相關資訊儲存在一個資料表或多個資料表中。 例如,在 School
資料庫中, Person
資料表包含單一資料表中學生和講師的相關資訊。 部分資料行僅適用于講師 (HireDate
) 、部分僅套用至學生 (EnrollmentDate
) ,有些則同時套用至 (LastName
FirstName
) 。
您可以設定 Entity Framework 來建立 Instructor
和 Student
繼承自實體的 Person
實體。 從單一資料庫資料表產生實體繼承結構的此模式稱為每個階層的 資料表 (TPH) 繼承。
針對課程, School
資料庫會使用不同的模式。 線上課程和現場課程會儲存在不同的資料表中,每個課程都有指向資料表的 Course
外鍵。 這兩個課程類型的通用資訊只會儲存在資料表中 Course
。
您可以設定 Entity Framework 資料模型, OnlineCourse
讓 和 OnsiteCourse
實體繼承自 Course
實體。 此模式會從每個類型的個別資料表產生實體繼承結構,每個個別資料表都會參考回儲存所有 類型 通用資料的資料表, (TPT) 繼承。
TPH 繼承模式通常會在 Entity Framework 中提供比 TPT 繼承模式更好的效能,因為 TPT 模式可能會導致複雜的聯結查詢。 本逐步解說示範如何實作 TPH 繼承。 您將執行下列步驟來執行此動作:
- 建立
Instructor
衍生自Person
的 實體Student
類型。 - 將與衍生實體相關的屬性從
Person
實體移至衍生實體。 - 在衍生型別中設定屬性的條件約束。
Person
使實體成為抽象實體。- 將每個衍生實體對應至
Person
資料表,其中包含指定如何判斷資料列是否Person
代表該衍生型別的條件。
新增 Instructor 和 Student 實體
開啟 SchoolModel.edmx 檔案,以滑鼠右鍵按一下設計工具中的未配置區域,選取 [ 新增],然後選取 [實體]。
在 [ 新增實體 ] 對話方塊中,將實體 Instructor
命名為 ,並將其 [基底類型 ] 選項設定為 Person
。
按一下 [確定]。 設計工具會 Instructor
建立衍生自實體的 Person
實體。 新的實體還沒有任何屬性。
重複此程式,以建立 Student
也衍生自 Person
的實體。
只有講師有雇用日期,因此您必須將該屬性從 Person
實體 Instructor
移至實體。 在實體中 Person
HireDate
,以滑鼠右鍵按一下 屬性,然後按一下 [ 剪下]。 然後在實體中的 [ 屬性 ] Instructor
上按一下滑鼠右鍵,然後按一下 [ 貼上]。
實體的 Instructor
雇用日期不可為 Null。 以滑鼠右鍵按一下 HireDate
屬性,按一下 [ 屬性],然後在 [ 屬性 ] 視窗中變更 Nullable
為 False
。
重複此程式,將 EnrollmentDate
屬性從 Person
實體 Student
移至實體。 請確定您也針對 屬性設定 Nullable
為 False
EnrollmentDate
。
現在,實體 Person
只有通用 Instructor
的屬性和 Student
(實體,除了您不移動的導覽屬性之外,您不會移動) ,實體只能當做繼承結構中的基底實體使用。 因此,您必須確保它永遠不會被視為獨立實體。 以滑鼠右鍵按一下 Person
實體,選取 [ 屬性],然後在 [ 屬性 ] 視窗中,將 Abstract 屬性的值變更為 True。
將講師和學生實體對應至人員資料表
現在您必須告訴 Entity Framework 如何區分 Instructor
資料庫中的 和 Student
實體。
以滑鼠右鍵按一下實體, Instructor
然後選取 [ 資料表對應]。 在 [ 對應詳細資料] 視窗中,按一下 [ 新增資料表] 或 [檢視 ],然後選取 [ 人員]。
按一下 [新增條件],然後選取 [HireDate]。
將 運算子 變更為 Is , 並將 Value / 屬性 變更為 Not Null。
重複實體的程式 Students
,指定此實體在資料行不是 Null 時 EnrollmentDate
對應至 Person
資料表。 然後儲存並關閉資料模型。
建置專案,以建立新的實體作為類別,並在設計工具中提供它們。
使用講師和學生實體
當您建立使用學生和講師資料的網頁時,您會將資料系結至 Person
實體集,並篩選 HireDate
或 EnrollmentDate
屬性,以將傳回的資料限制給學生或講師。 不過,現在當您將每個資料來源控制項系結至 Person
實體集時,您可以指定只 Student
選取或 Instructor
實體類型。 由於 Entity Framework 知道如何區分實體集中的學生和講師 Person
,因此您可以移除 Where
手動輸入的屬性設定來執行此動作。
在 Visual Studio Designer中,您可以指定控制項應該在精靈的EntityTypeFilter下拉式方 Configure Data Source
塊中選取的實體類型 EntityDataSource
,如下列範例所示。
在 [ 屬性 ] 視窗中,您可以移除 Where
不再需要的子句值,如下列範例所示。
不過,因為您已將控制項的標記 EntityDataSource
變更為使用 ContextTypeName
屬性,所以您無法在已建立的控制項上 EntityDataSource
執行 [設定資料來源精靈]。 因此,您將改為變更標記來進行必要的變更。
開啟 Students.aspx 頁面。 在 控制項中 StudentsEntityDataSource
Where
,移除 屬性並新增 EntityTypeFilter="Student"
屬性。 標記現在會類似下列範例:
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People" EntityTypeFilter="Student"
Include="StudentGrades"
EnableDelete="True" EnableUpdate="True"
OrderBy="it.LastName" >
</asp:EntityDataSource>
EntityTypeFilter
設定屬性可確保 EntityDataSource
控制項只會選取指定的實體類型。 如果您想要同時 Student
擷取 和 Instructor
實體類型,則不會設定此屬性。 (只有在您使用控制項進行唯讀資料存取時,您才能選擇擷取具有一個 EntityDataSource
控制項的多個實體類型。如果您使用 EntityDataSource
控制項來插入、更新或刪除實體,而且它系結至的實體集可以包含多個類型,則只能使用一個實體類型,而且您必須設定此屬性。)
重複控制項的程式 SearchEntityDataSource
,但只移除選取 Student
實體的屬性 Where
部分,而不是完全移除 屬性。 控制項的開頭標記現在會類似下列範例:
<asp:EntityDataSource ID="SearchEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People" EntityTypeFilter="Student"
Where="it.FirstMidName Like '%' + @StudentName + '%' or it.LastName Like '%' + @StudentName + '%'" >
執行頁面以確認它仍如先前一樣運作。
更新您在先前教學課程中建立的下列頁面,使其使用新的 Student
和 Instructor
實體,而不是 Person
實體,然後執行它們以確認它們如先前一樣運作:
在 StudentsAdd.aspx中,將 新增
EntityTypeFilter="Student"
至StudentsEntityDataSource
控制項。 標記現在會類似下列範例:<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" EnableInsert="True" </asp:EntityDataSource>
在About.aspx中
StudentStatisticsEntityDataSource
,新增EntityTypeFilter="Student"
至 控制項並移除Where="it.EnrollmentDate is not null"
。 標記現在會類似下列範例:<asp:EntityDataSource ID="StudentStatisticsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" Select="it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents" OrderBy="it.EnrollmentDate" GroupBy="it.EnrollmentDate" > </asp:EntityDataSource>
在 Instructors.aspx 和 InstructorsCourses.aspx中,新增
EntityTypeFilter="Instructor"
至InstructorsEntityDataSource
控制項並移除Where="it.HireDate is not null"
。 Instructors.aspx中的標記現在類似下列範例:<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false" EntitySetName="People" EntityTypeFilter="Instructor" Include="OfficeAssignment" EnableUpdate="True"> </asp:EntityDataSource>
InstructorsCourses.aspx中的標記現在類似下列範例:
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Instructor" Select="it.LastName + ',' + it.FirstMidName AS Name, it.PersonID"> </asp:EntityDataSource>
由於這些變更,您已透過數種方式改善 Contoso University 應用程式的可維護性。 您已將選取專案和驗證邏輯移出 UI 層 (.aspx 標記) ,並讓它成為資料存取層不可或缺的一部分。 這有助於將應用程式程式碼與未來對資料庫架構或資料模型所做的變更隔離。 例如,您可以決定學生可能會被雇用為教師的輔助工具,因此會取得雇用日期。 然後,您可以新增屬性來區分學生與講師,並更新資料模型。 除了您想要為學生顯示雇用日期之外,Web 應用程式中不需要變更任何程式碼。 新增 Instructor
和 Student
實體的另一個優點是,您的程式碼比參考 Person
實際學生或講師的物件更容易瞭解。
您現在已瞭解如何在 Entity Framework 中實作繼承模式。 在下列教學課程中,您將瞭解如何使用預存程式,以更充分掌控 Entity Framework 存取資料庫的方式。