消費者入門 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 控制項來處理相關資料。 您已在導覽屬性中顯示多個階層層級和編輯的資料。 在本教學課程中,您將藉由新增和刪除關聯性,以及新增與現有實體有關聯性的新實體,繼續處理相關資料。

您將建立一個頁面,以新增指派給部門的課程。 部門已經存在,而且當您建立新課程時,您會同時建立其與現有部門之間的關聯性。

Internet Explorer 視窗的螢幕擷取畫面,其中顯示 [新增課程] 檢視,其中包含 [識別碼]、[標題] 和 [點數] 文字欄位和 [部門] 下拉式清單。

您也會建立一個頁面,將講師指派給課程,以使用多對多關聯性, (新增您選取) 兩個實體之間的關聯性,或從課程中移除講師, (移除您選取) 兩個實體之間的關聯性。 在資料庫中,新增講師與課程之間的關聯性會導致將新的資料列新增至 CourseInstructor 關聯資料表;移除關聯性牽涉到從 CourseInstructor 關聯資料表中刪除資料列。 不過,您可以在 Entity Framework 中設定導覽屬性來執行這項操作,而不需明確參考 CourseInstructor 資料表。

Internet Explorer 視窗的螢幕擷取畫面,其中顯示 [將講師指派給課程] 或 [從課程移除] 檢視。

將具有關聯性的實體新增至現有實體

建立名為CoursesAdd.aspx的新網頁,其使用Site.Master 主版頁面,並將下列標記新增至名為 Content2Content 控制項:

<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 使用。 範本欄位提供下拉式清單來選取部門。 下拉式清單會使用 EvalBind 結至 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 實體屬性的值 CourseDropDownList

Entity Framework 會負責將此課程新增至 Courses 相關聯 Department 實體的導覽屬性。 它也會將部門新增至 Department 實體的 Course 導覽屬性。

執行頁面。

Internet Explorer 視窗的螢幕擷取畫面,其中顯示 [新增課程] 檢視,其中包含 [識別碼]、[標題] 和 [點數] 文字欄位和 [部門] 下拉式清單。

輸入識別碼、標題、點數,然後選取部門,然後按一下 [ 插入]。

執行 Courses.aspx 頁面,然後選取相同的部門以查看新課程。

Image03

使用多對多關聯性

實體集與 People 實體集之間的 Courses 關聯性是多對多關聯性。 Course實體具有名為 People 的導覽屬性,可以包含零、一或多個相關 Person 實體, (代表指派給該課程的講師) 。 Person而且實體具有名為 Courses 的導覽屬性,該屬性可以包含零、一或多個相關 Course 實體 (代表講師指派給教學) 的課程。 一位講師可能會教導多個課程,而一個課程可能由多個講師教授。 在逐步解說的本節中,您將藉由更新相關實體的導覽屬性,來新增和移除 和 Course 實體之間的 Person 關聯性。

建立名為InstructorsCourses.aspx的新網頁,以使用Site.Master 主版頁面,並將下列標記新增至名為 Content2Content 控制項:

<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 ,以擷取講師的名稱和 PersonIDPerson 實體。 控制項 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();
}

執行頁面。

Internet Explorer 視窗的螢幕擷取畫面,其中顯示具有對應下拉式清單的 [將講師指派給課程] 或 [從課程移除] 檢視。

選取講師。 [ 指派課程 ] 下拉式清單會顯示講師未教授的課程,而 [移除課程 ] 下拉式清單會顯示講師已指派的課程。 在 [ 指派課程] 區段中,選取課程,然後按一下 [ 指派]。 課程會移至 [ 移除課程] 下拉式清單。 在 [ 移除課程 ] 區段中選取課程,然後按一下 [ 移除]。 課程會移至 [指派課程] 下拉式清單。

您現在已看到一些更多使用相關資料的方式。 在下列教學課程中,您將瞭解如何在資料模型中使用繼承,以改善應用程式的可維護性。