消費者入門 Entity Framework 4.0 Database First 和 ASP.NET 4 Web Form - 第 5 部分
作者 :Tom Dykstra
Contoso University 範例 Web 應用程式示範如何使用 Entity Framework 4.0 和 Visual Studio 2010 建立 ASP.NET Web Forms應用程式。 如需教學課程系列的相關資訊,請參閱系列中的第一個教學課程
使用相關資料,繼續
在上一個教學課程中,您已開始使用 EntityDataSource
控制項來處理相關資料。 您已在導覽屬性中顯示多個階層層級和編輯的資料。 在本教學課程中,您將藉由新增和刪除關聯性,以及新增與現有實體有關聯性的新實體,繼續處理相關資料。
您將建立一個頁面,以新增指派給部門的課程。 部門已經存在,而且當您建立新課程時,您會同時建立其與現有部門之間的關聯性。
您也會建立一個頁面,將講師指派給課程,以使用多對多關聯性, (新增您選取) 兩個實體之間的關聯性,或從課程中移除講師, (移除您選取) 兩個實體之間的關聯性。 在資料庫中,新增講師與課程之間的關聯性會導致將新的資料列新增至 CourseInstructor
關聯資料表;移除關聯性牽涉到從 CourseInstructor
關聯資料表中刪除資料列。 不過,您可以在 Entity Framework 中設定導覽屬性來執行這項操作,而不需明確參考 CourseInstructor
資料表。
將具有關聯性的實體新增至現有實體
建立名為CoursesAdd.aspx的新網頁,其使用Site.Master 主版頁面,並將下列標記新增至名為 Content2
的 Content
控制項:
<h2>Add Courses</h2>
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="Courses"
EnableInsert="True" EnableDelete="True" >
</asp:EntityDataSource>
<asp:DetailsView ID="CoursesDetailsView" runat="server" AutoGenerateRows="False"
DataSourceID="CoursesEntityDataSource" DataKeyNames="CourseID"
DefaultMode="Insert" oniteminserting="CoursesDetailsView_ItemInserting">
<Fields>
<asp:BoundField DataField="CourseID" HeaderText="ID" />
<asp:BoundField DataField="Title" HeaderText="Title" />
<asp:BoundField DataField="Credits" HeaderText="Credits" />
<asp:TemplateField HeaderText="Department">
<InsertItemTemplate>
<asp:EntityDataSource ID="DepartmentsEntityDataSource" runat="server" ConnectionString="name=SchoolEntities"
DefaultContainerName="SchoolEntities" EnableDelete="True" EnableFlattening="False"
EntitySetName="Departments" EntityTypeFilter="Department">
</asp:EntityDataSource>
<asp:DropDownList ID="DepartmentsDropDownList" runat="server" DataSourceID="DepartmentsEntityDataSource"
DataTextField="Name" DataValueField="DepartmentID"
oninit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
此標記會建立控制項 EntityDataSource
,以選取課程、啟用插入,以及指定事件的處理常式 Inserting
。 建立新 Course
實體時,您將使用 處理常式來更新 Department
導覽屬性。
標記也會建立 DetailsView
控制項,以用於新增 Course
實體。 標記會針對 Course
實體屬性使用系結欄位。 您必須輸入值, CourseID
因為這是系統產生的識別碼欄位。 相反地,這是必須在建立課程時手動指定的課程編號。
您可以使用導覽屬性的範本欄位, Department
因為導覽屬性不能與控制項搭配 BoundField
使用。 範本欄位提供下拉式清單來選取部門。 下拉式清單會使用 Eval
系 Bind
結至 Departments
實體集,而不是 再次系結,因為您無法直接系結導覽屬性以更新它們。 您可以指定控制項 Init
事件的處理常式 DropDownList
,以便儲存控制項的參考,以供更新 DepartmentID
外鍵的程式碼使用。
在 CoursesAdd.aspx.cs 的部分類別宣告之後,新增類別欄位來保存控制項的 DepartmentsDropDownList
參考:
private DropDownList departmentDropDownList;
新增 控制項 Init
事件的處理常式 DepartmentsDropDownList
,以便儲存控制項的參考。 這可讓您取得使用者輸入的值,並用它來更新 DepartmentID
實體的值 Course
。
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
departmentDropDownList = sender as DropDownList;
}
新增 控制項 Inserting
事件的處理常式 DetailsView
:
protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
e.Values["DepartmentID"] = departmentID;
}
當使用者按一下 Insert
時, Inserting
會在插入新記錄之前引發 事件。 處理常式中的程式碼會從 控制項取得 DepartmentID
,並使用它來設定將用於 DepartmentID
實體屬性的值 Course
。 DropDownList
Entity Framework 會負責將此課程新增至 Courses
相關聯 Department
實體的導覽屬性。 它也會將部門新增至 Department
實體的 Course
導覽屬性。
執行頁面。
輸入識別碼、標題、點數,然後選取部門,然後按一下 [ 插入]。
執行 Courses.aspx 頁面,然後選取相同的部門以查看新課程。
使用多對多關聯性
實體集與 People
實體集之間的 Courses
關聯性是多對多關聯性。 Course
實體具有名為 People
的導覽屬性,可以包含零、一或多個相關 Person
實體, (代表指派給該課程的講師) 。 Person
而且實體具有名為 Courses
的導覽屬性,該屬性可以包含零、一或多個相關 Course
實體 (代表講師指派給教學) 的課程。 一位講師可能會教導多個課程,而一個課程可能由多個講師教授。 在逐步解說的本節中,您將藉由更新相關實體的導覽屬性,來新增和移除 和 Course
實體之間的 Person
關聯性。
建立名為InstructorsCourses.aspx的新網頁,以使用Site.Master 主版頁面,並將下列標記新增至名為 Content2
的 Content
控制項:
<h2>Assign Instructors to Courses or Remove from Courses</h2>
<br />
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
Where="it.HireDate is not null" Select="it.LastName + ', ' + it.FirstMidName AS Name, it.PersonID">
</asp:EntityDataSource>
Select an Instructor:
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsEntityDataSource"
AutoPostBack="true" DataTextField="Name" DataValueField="PersonID"
OnSelectedIndexChanged="InstructorsDropDownList_SelectedIndexChanged"
OnDataBound="InstructorsDropDownList_DataBound">
</asp:DropDownList>
<h3>
Assign a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="UnassignedCoursesDropDownList" runat="server"
DataTextField="Title" DataValueField="CourseID">
</asp:DropDownList>
<br />
<asp:Button ID="AssignCourseButton" runat="server" Text="Assign" OnClick="AssignCourseButton_Click" />
<br />
<asp:Label ID="CourseAssignedLabel" runat="server" Visible="false" Text="Assignment successful"></asp:Label>
<br />
<h3>
Remove a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="AssignedCoursesDropDownList" runat="server"
DataTextField="title" DataValueField="courseiD">
</asp:DropDownList>
<br />
<asp:Button ID="RemoveCourseButton" runat="server" Text="Remove" OnClick="RemoveCourseButton_Click" />
<br />
<asp:Label ID="CourseRemovedLabel" runat="server" Visible="false" Text="Removal successful"></asp:Label>
此標記會建立控制項 EntityDataSource
,以擷取講師的名稱和 PersonID
Person
實體。 控制項 DropDrownList
系結至 EntityDataSource
控制項。 控制項 DropDownList
會指定 事件的處理常式 DataBound
。 您將使用此處理程式來資料系結顯示課程的兩個下拉式清單。
標記也會建立下列控制項群組,以用於將課程指派給選取的講師:
DropDownList
用於選取要指派課程的控制項。 此控制項會填入目前未指派給所選講師的課程。- 起始
Button
指派的控制項。 - 如果
Label
指派失敗,顯示錯誤訊息的控制項。
最後,標記也會建立一組控制項,以用來從選取的講師中移除課程。
在 InstructorsCourses.aspx.cs中,新增 using 語句:
using ContosoUniversity.DAL;
新增方法,以填入顯示課程的兩個下拉式清單:
private void PopulateDropDownLists()
{
using (var context = new SchoolEntities())
{
var allCourses = (from c in context.Courses
select c).ToList();
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People.Include("Courses")
where p.PersonID == instructorID
select p).First();
var assignedCourses = instructor.Courses.ToList();
var unassignedCourses = allCourses.Except(assignedCourses.AsEnumerable()).ToList();
UnassignedCoursesDropDownList.DataSource = unassignedCourses;
UnassignedCoursesDropDownList.DataBind();
UnassignedCoursesDropDownList.Visible = true;
AssignedCoursesDropDownList.DataSource = assignedCourses;
AssignedCoursesDropDownList.DataBind();
AssignedCoursesDropDownList.Visible = true;
}
}
此程式碼會從 Courses
實體集取得所有課程,並從所選講師實體的 Person
導覽屬性取得課程 Courses
。 然後,它會決定指派給該講師的課程,並據以填入下拉式清單。
新增按鈕 Click
事件的處理常式 Assign
:
protected void AssignCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(UnassignedCoursesDropDownList.SelectedValue);
var course = (from c in context.Courses
where c.CourseID == courseID
select c).First();
instructor.Courses.Add(course);
try
{
context.SaveChanges();
PopulateDropDownLists();
CourseAssignedLabel.Text = "Assignment successful.";
}
catch (Exception)
{
CourseAssignedLabel.Text = "Assignment unsuccessful.";
//Add code to log the error.
}
CourseAssignedLabel.Visible = true;
}
}
此程式碼會 Person
取得所選講師的實體、取得 Course
所選課程的實體,並將選取的課程新增至 Courses
講師 Person
實體的導覽屬性。 然後,它會儲存資料庫的變更,並重新填入下拉式清單,以便立即看到結果。
新增按鈕 Click
事件的處理常式 Remove
:
protected void RemoveCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(AssignedCoursesDropDownList.SelectedValue);
var courses = instructor.Courses;
var courseToRemove = new Course();
foreach (Course c in courses)
{
if (c.CourseID == courseID)
{
courseToRemove = c;
break;
}
}
try
{
courses.Remove(courseToRemove);
context.SaveChanges();
PopulateDropDownLists();
CourseRemovedLabel.Text = "Removal successful.";
}
catch (Exception)
{
CourseRemovedLabel.Text = "Removal unsuccessful.";
//Add code to log the error.
}
CourseRemovedLabel.Visible = true;
}
}
此程式碼會取得 Person
所選講師的實體、取得 Course
所選課程的實體,並從實體的 Courses
導覽屬性中移除選取 Person
的課程。 然後,它會儲存資料庫的變更,並重新填入下拉式清單,以便立即看到結果。
將程式碼新增至 Page_Load
方法,以確保在沒有報告錯誤時看不到錯誤訊息,並針對講師下拉式清單的 和 SelectedIndexChanged
事件新增處理常式 DataBound
,以填入課程下拉式清單:
protected void Page_Load(object sender, EventArgs e)
{
CourseAssignedLabel.Visible = false;
CourseRemovedLabel.Visible = false;
}
protected void InstructorsDropDownList_DataBound(object sender, EventArgs e)
{
PopulateDropDownLists();
}
protected void InstructorsDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateDropDownLists();
}
執行頁面。
選取講師。 [ 指派課程 ] 下拉式清單會顯示講師未教授的課程,而 [移除課程 ] 下拉式清單會顯示講師已指派的課程。 在 [ 指派課程] 區段中,選取課程,然後按一下 [ 指派]。 課程會移至 [ 移除課程] 下拉式清單。 在 [ 移除課程 ] 區段中選取課程,然後按一下 [ 移除]。 課程會移至 [指派課程] 下拉式清單。
您現在已看到一些更多使用相關資料的方式。 在下列教學課程中,您將瞭解如何在資料模型中使用繼承,以改善應用程式的可維護性。