消費者入門 Entity Framework 4.0 Database First 和 ASP.NET 4 Web Form - 第 2 部分
By Tom Dykstra
Contoso University 範例 Web 應用程式示範如何使用 Entity Framework 4.0 和 Visual Studio 2010 建立 ASP.NET Web Forms應用程式。 如需教學課程系列的相關資訊,請參閱 系列中的第一個教學課程
EntityDataSource 控制項
在上一個教學課程中,您已建立網站、資料庫和資料模型。 在本教學課程中,您會使用 EntityDataSource
ASP.NET 提供的控制項,以便輕鬆地使用 Entity Framework 資料模型。 您將建立 GridView
控制項來顯示和編輯學生資料、 DetailsView
新增新學生的控制項,以及 DropDownList
選取部門 (的控制項,稍後您將用來顯示相關聯的課程) 。
請注意,在此應用程式中,您不會將輸入驗證新增至更新資料庫的頁面,而某些錯誤處理不會像生產應用程式中所需的一樣強固。 這會讓教學課程著重于 Entity Framework,並讓它變得太長。 如需如何將這些功能新增至應用程式的詳細資訊,請參閱在頁面和應用程式中驗證 ASP.NET ASP.NET Web Pages中的使用者輸入和錯誤處理。
新增和設定 EntityDataSource 控制項
首先,您將設定 EntityDataSource
控制項以從 People
實體集讀取 Person
實體。
請確定您已開啟 Visual Studio,並且正在使用您在第 1 部分中建立的專案。 如果您自從建立資料模型或上次變更之後尚未建置專案,請立即建置專案。 在建置專案之前,資料模型的變更不會提供給設計工具使用。
使用主版頁面範本使用 Web 表單 建立新的網頁,並將它命名為 Students.aspx。
將 Site.Master 指定為主版頁面。 您為這些教學課程建立的所有頁面都會使用此主版頁面。
在 [來源 ] 檢視中,將標題新增 h2
至 Content
名為 的 Content2
控制項,如下列範例所示:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
</asp:Content>
從[工具箱] 的 [資料] 索引標籤中,將控制項拖曳 EntityDataSource
至頁面,將它放在標題下方,然後將識別碼變更為 StudentsEntityDataSource
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server">
</asp:EntityDataSource>
</asp:Content>
切換至 [設計] 檢視,按一下資料來源控制項的智慧標籤,然後按一下 [ 設定 資料來源] 以啟動 [ 設定資料來源 精靈]。
在 [ 設定 ObjectCoNtext 精 靈] 步驟中,選取 [SchoolEntities ] 作為 [具名連線] 的值,然後選取 [SchoolEntities ] 作為 DefaultContainerName 值。 然後按一下 [下一步] 。
注意:如果您此時收到下列對話方塊,您必須先建置專案,再繼續進行。
在 [設定資料選取] 步驟中,選取[人員] 作為EntitySetName的值。 在 [ 選取] 底下,確定已選取 [ 選取 A ] 核取方塊。 然後選取啟用更新和刪除的選項。 完成時,按一下 [ 完成]。
設定資料庫規則以允許刪除
您將建立一個頁面,讓使用者從 Person
資料表中刪除學生,此資料表與其他資料表有三個關聯性, (Course
、 StudentGrade
和 OfficeAssignment
) 。 根據預設,如果其中一個資料表中有相關資料列,資料庫將無法刪除 中的資料 Person
列。 您可以先手動刪除相關資料列,也可以設定資料庫,以在刪除資料 Person
列時自動刪除它們。 針對本教學課程中的學生記錄,您將設定資料庫來自動刪除相關資料。 因為學生只能在資料表中 StudentGrade
擁有相關資料列,所以您只需要設定三個關聯性的其中一個。
如果您使用從本教學課程隨附的專案下載的 School.mdf 檔案,您可以略過本節,因為這些組態變更已經完成。 如果您藉由執行腳本來建立資料庫,請執行下列程式來設定資料庫。
在 [伺服器總管] 中,開啟您在第 1 部分中建立的資料庫關係圖。 以滑鼠右鍵按一下 和 StudentGrade
之間的關聯性, (資料表之間的 Person
行) ,然後選取 [屬性]。
在 [ 屬性 ] 視窗中,展開 INSERT 和 UPDATE 規格 ,並將 DeleteRule 屬性設定為 Cascade。
儲存並關閉圖表。 如果系統詢問您是否要更新資料庫,請按一下 [ 是]。
若要確定模型會讓記憶體中的實體與資料庫執行的動作保持同步,您必須在資料模型中設定對應的規則。 開啟SchoolModel.edmx,以滑鼠右鍵按一下 和 StudentGrade
之間的 Person
關聯線,然後選取 [屬性]。
在 [ 屬性] 視窗中,將 End1 OnDelete 設定為 Cascade。
儲存並關閉 SchoolModel.edmx 檔案,然後重建專案。
一般而言,當資料庫變更時,您有數個如何同步處理模型的選項:
- 對於某些類型的變更 (,例如新增或重新整理資料表、檢視或預存程式) ,請在設計工具中按一下滑鼠右鍵,然後從資料庫選取 [ 更新模型 ],讓設計工具自動進行變更。
- 重新產生資料模型。
- 像這樣進行手動更新。
在此情況下,您可以重新產生模型或重新整理受關聯性變更影響的資料表,但您必須再次變更功能變數名稱, (FirstName
變更為 FirstMidName
) 。
使用 GridView 控制項讀取和更新實體
在本節中,您將使用 GridView
控制項來顯示、更新或刪除學生。
開啟或切換至 Students.aspx ,並切換至 [設計] 檢視。 從[工具箱] 的 [資料] 索引標籤中,將控制項拖曳 GridView
到控制項右邊 EntityDataSource
,將它 StudentsGridView
命名為 ,按一下智慧標籤,然後選取StudentsEntityDataSource作為資料來源。
如果系統提示您確認) ,請按一下 [ 重新整理架構 ] (按一下 [ 是 ],然後按一下 [ 啟用分頁]、[ 啟用排序]、[ 啟用編輯] 和 [ 啟用刪除]。
按一下 [編輯資料行]。
在 [ 選取的欄位] 方塊 中,刪除 PersonID、 LastName和 HireDate。 您通常不會向使用者顯示記錄索引鍵、雇用日期與學生無關,而且您會將這兩個部分的名稱放在一個欄位中,因此您只需要其中一個名稱欄位。)
選取 [FirstMidName] 欄位,然後按一下 [ 將此欄位轉換成 TemplateField]。
針對 EnrollmentDate執行相同的動作。
按一下 [確定 ],然後切換至 [來源 ] 檢視。 其餘的變更將更容易直接在標記中執行。 控制項 GridView
標記現在看起來像下列範例。
<asp:GridView ID="StudentsGridView" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="PersonID"
DataSourceID="StudentsEntityDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:TemplateField HeaderText="FirstMidName" SortExpression="FirstMidName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="EnrollmentDate" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
命令欄位後面的第一個資料行是目前顯示名字的範本欄位。 變更此範本欄位的標記,如下所示:
<asp:TemplateField HeaderText="Name" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="LastNameTextBox" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox>
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
<asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
在顯示模式中,兩 Label
個控制項會顯示名字和姓氏。 在編輯模式中,會提供兩個文字方塊,讓您可以變更名字和姓氏。 如同 Label
顯示模式中的控制項,您可以使用 Bind
和 Eval
運算式,就像直接連接到資料庫的資料來源控制項 ASP.NET 一樣。 唯一的差異在於您要指定實體屬性,而不是資料庫資料行。
最後一個資料行是顯示註冊日期的範本欄位。 變更此欄位的標記,如下所示:
<asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="EnrollmentDateTextBox" runat="server" Text='<%# Bind("EnrollmentDate", "{0:d}") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="EnrollmentDateLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
在顯示和編輯模式中,格式字串 「{0,d}」 會導致日期以「簡短日期」格式顯示。 (您的電腦可能會設定為與本教學課程中顯示的螢幕影像不同顯示此格式。)
請注意,在上述每個範本欄位中,設計工具預設會使用 Bind
運算式,但您已將該運算式變更為 Eval
元素中的 ItemTemplate
運算式。 運算式 Bind
可讓您在控制項屬性中使用 GridView
資料,以防您需要存取程式碼中的資料。 在此頁面中,您不需要在程式碼中存取此資料,因此您可以使用 Eval
更有效率的 。 如需詳細資訊,請參閱 將資料從資料控制項取出。
修改 EntityDataSource 控制項標記以改善效能
在 控制項的標記中 EntityDataSource
,移除 ConnectionString
和 DefaultContainerName
屬性,並將其取代為 ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
屬性。 這是每次建立 EntityDataSource
控制項時應該所做的變更,除非您需要使用不同于物件內容類別別中硬式編碼的連接。 ContextTypeName
使用 屬性可提供下列優點:
- 效能較佳。
EntityDataSource
當控制項使用ConnectionString
和DefaultContainerName
屬性初始化資料模型時,它會對每個要求執行額外的工作來載入中繼資料。 如果您指定ContextTypeName
屬性,則不需要這樣做。 - 預設會在產生的物件內容類別別中開啟延遲載入, (
SchoolEntities
例如本教學課程) Entity Framework 4.0。 這表示當您需要時,導覽屬性會自動載入相關資料。 本教學課程稍後會更詳細地說明延遲載入。 - 在此案例中,您已套用至物件內容類別別的任何自訂 (,
SchoolEntities
類別) 將可供使用 控制項的EntityDataSource
控制項使用。 自訂物件內容類別別是本教學課程系列未涵蓋的進階主題。 如需詳細資訊,請參閱 擴充 Entity Framework 產生的類型。
標記現在會類似下列範例, (屬性的順序可能不同) :
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
EnableDelete="True" EnableUpdate="True">
</asp:EntityDataSource>
屬性 EnableFlattening
是指舊版 Entity Framework 中所需的功能,因為外鍵資料行並未公開為實體屬性。 目前的版本可讓您使用 外鍵關聯,這表示外鍵屬性會公開給除了多對多關聯之外的所有關聯。 如果您的實體具有外鍵屬性且沒有 複雜類型,您可以將此屬性設定為 False
。 請勿從標記中移除 屬性,因為預設值為 True
。 如需詳細資訊,請參閱 將物件扁平化 (EntityDataSource) 。
執行頁面,您會看到學生和員工清單, (您將在下一個教學課程) 只篩選學生。 名字和姓氏會一起顯示。
若要排序顯示,請按一下資料行名稱。
按一下任何資料列中的 [編輯 ]。 文字方塊隨即顯示,您可以在其中變更名字和姓氏。
[ 刪除] 按鈕也可以運作。 針對具有註冊日期且資料列消失的資料列按一下 [刪除]。 (沒有註冊日期的資料列代表講師,您可能會收到參考完整性錯誤。在下一個教學課程中,您將篩選此清單,只包含 students.)
顯示導覽屬性中的資料
現在假設您想要知道每個學生註冊的課程數目。 Entity Framework 會在實體的 StudentGrades
Person
導覽屬性中提供該資訊。 因為資料庫設計不允許學生在課程中註冊,而不需要指派成績,所以在本教學課程中 StudentGrade
,您可以假設在與課程相關聯的資料表資料列中有一個資料列與在課程中註冊相同。 (導覽 Courses
屬性僅適用于 instructors.)
當您使用 ContextTypeName
控制項的 EntityDataSource
屬性時,Entity Framework 會在存取該屬性時自動擷取導覽屬性的資訊。 這稱為 延遲載入。 不過,這可能會沒有效率,因為它會在每次需要其他資訊時,對資料庫產生個別呼叫。 如果您需要控制項所傳回 EntityDataSource
之每個實體的導覽屬性資料,則擷取相關資料以及單一呼叫資料庫中的實體本身會更有效率。 這稱為 積極式載入,您可以藉由設定 Include
控制項的 屬性來指定導覽屬性的 EntityDataSource
積極式載入。
在 Students.aspx中,您想要顯示每位學生的課程數目,因此積極式載入是最佳選擇。 如果您顯示所有學生,但只針對其中幾個學生顯示課程數目, (這除了標記) 之外,還需要撰寫某些程式碼,則延遲載入可能是較佳的選擇。
開啟或切換至 Students.aspx、切換至 [設計] 檢視、選取 StudentsEntityDataSource
,然後在 [ 屬性 ] 視窗中,將 [包含 ] 屬性設定為 StudentGrades。 (如果您想要取得多個導覽屬性,您可以指定以逗號分隔的名稱,例如 StudentGrades、Courses.)
切換至 [來源 ] 檢視。 在 控制項中 StudentsGridView
,在最後一個專案 asp:TemplateField
之後,新增下列新範本欄位:
<asp:TemplateField HeaderText="Number of Courses">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("StudentGrades.Count") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
在運算式中 Eval
,您可以參考導覽屬性 StudentGrades
。 因為這個屬性包含集合,所以它具有 Count
屬性,可讓您用來顯示註冊學生的課程數目。 在稍後的教學課程中,您將瞭解如何顯示包含單一實體而非集合之導覽屬性的資料。 (請注意,您無法使用 BoundField
元素來顯示導覽屬性中的資料。)
執行頁面,您現在會看到每個學生註冊的課程數目。
使用 DetailsView 控制項插入實體
下一個步驟是建立具有 DetailsView
控制項的頁面,讓您新增新學生。 關閉瀏覽器,然後使用 Site.Master 主版頁面建立新的網頁。 將 [ StudentsAdd.aspx] 頁面命名為 ,然後切換至 [來源 ] 檢視。
新增下列標記,以取代名為 Content2
之 Content
控制項的現有標記:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add New Students</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EnableInsert="True" EntitySetName="People">
</asp:EntityDataSource>
<asp:DetailsView ID="StudentsDetailsView" runat="server"
DataSourceID="StudentsEntityDataSource" AutoGenerateRows="False"
DefaultMode="Insert">
<Fields>
<asp:BoundField DataField="FirstMidName" HeaderText="First Name"
SortExpression="FirstMidName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name"
SortExpression="LastName" />
<asp:BoundField DataField="EnrollmentDate" HeaderText="Enrollment Date"
SortExpression="EnrollmentDate" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
</asp:Content>
此標記會建立一個 EntityDataSource
控制項,類似于您在 Students.aspx中建立的控制項,但會啟用插入。 GridView
和 控制項一樣,控制項的 DetailsView
系結欄位會與直接連接到資料庫的資料控制項一樣編碼,不同之處在于它們參考實體屬性。 在此情況下, DetailsView
控制項僅用於插入資料列,因此您已將預設模式設定為 Insert
。
執行頁面並新增學生。
插入新學生之後不會發生任何事,但如果您現在執行 Students.aspx,您會看到新的學生資訊。
在Drop-Down清單中顯示資料
在下列步驟中,您將使用 EntityDataSource
控制項將資料系結 DropDownList
至實體集。 在本教學課程的這個部分中,您不會對此清單執行太多動作。 不過,在後續部分中,您將使用清單讓使用者選取部門來顯示與部門相關聯的課程。
建立名為 Courses.aspx的新網頁。 在 [來源 ] 檢視中,將標題新增至 Content
名為 Content2
的控制項:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Courses by Department</h2>
</asp:Content>
在 [設計 ] 檢視中,將控制項新增 EntityDataSource
至頁面,但這次將它命名為 DepartmentsEntityDataSource
除外。 選取 [Departments ] 作為 [EntitySetName ] 值,然後只選取 [DepartmentID ] 和 [ 名稱] 屬性。
從[工具箱] 的 [標準] 索引標籤中,將控制項拖曳 DropDownList
至頁面,將它 DepartmentsDropDownList
命名為 ,按一下智慧標籤,然後選取 [選擇資料來源] 以啟動[資料來源設定精靈]。
在 [ 選擇資料來源 ] 步驟中,選取 [DepartmentsEntityDataSource ] 作為資料來源,按一下 [ 重新整理架構],然後選取 [ 名稱 ] 作為要顯示的資料欄位,並將 DepartmentID 顯示為值資料欄位。 按一下 [確定]。
您使用 Entity Framework 將資料系結控制項的方法與其他 ASP.NET 資料來源控制項相同,但您指定實體和實體屬性除外。
切換至 [來源 ] 檢視,並在控制項之前 DropDownList
立即新增 「選取部門:」。
Select a department:
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="EntityDataSource1" DataTextField="Name"
DataValueField="DepartmentID">
</asp:DropDownList>
提醒您,將 和 DefaultContainerName
屬性取代 ConnectionString
為 ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
屬性,以變更此時控制項的標記 EntityDataSource
。 在變更 EntityDataSource
控制項標記之前,最好等到建立與資料來源控制項連結的資料繫結控制項之後,因為在您進行變更之後,設計工具不會在資料繫結控制項中提供 [ 重新整理架構 ] 選項。
執行頁面,您可以從下拉式清單中選取部門。
這會完成使用 控制項的 EntityDataSource
簡介。 使用此控制項通常與使用其他 ASP.NET 資料來源控制項不同,不同之處在于參考實體和資料行,而不是資料表和資料行。 唯一的例外狀況是當您想要存取導覽屬性時。 在下一個教學課程中,您會看到搭配控制項使用的 EntityDataSource
語法可能也會與您篩選、分組和排序資料時的其他資料來源控制項不同。