Entity Framework 4.0 Database First と ASP.NET 4 Web Forms を使用したはじめに - パート 5

作成者: Tom Dykstra

Contoso University サンプル Web アプリケーションは、Entity Framework 4.0 と Visual Studio 2010 を使用して ASP.NET Web Forms アプリケーションを作成する方法を示しています。 チュートリアル シリーズの詳細については、シリーズの最初のチュートリアルを参照してください

前のチュートリアルでは、 コントロールを使用 EntityDataSource して関連データを操作し始めました。 複数レベルの階層と編集されたデータをナビゲーション プロパティに表示しました。 このチュートリアルでは、リレーションシップを追加および削除し、既存のエンティティにリレーションシップを持つ新しいエンティティを追加することで、関連データを引き続き操作します。

部署に割り当てられているコースを追加するページを作成します。 部門は既に存在し、新しいコースを作成すると同時に、その部門と既存の部門の間に関係が確立されます。

[インターネット エクスプローラー] ウィンドウのスクリーンショット。ID、タイトル、クレジットのテキスト フィールドと [部署] ドロップダウンが表示された [コースの追加] ビューが表示されています。

また、コースに講師を割り当てる (選択した 2 つのエンティティ間のリレーションシップを追加する) か、コースから講師を削除する (選択した 2 つのエンティティ間のリレーションシップを削除する) ことも、多対多リレーションシップで動作するページを作成します。 データベースで、インストラクターとコースの間にリレーションシップを追加すると、関連付けテーブルに CourseInstructor 新しい行が追加されます。リレーションシップを削除するには、関連付けテーブルから行を削除する CourseInstructor 必要があります。 ただし、エンティティ フレームワークでは、テーブルを明示的に参照せずにナビゲーション プロパティを CourseInstructor 設定することでこれを行います。

[インターネット エクスプローラー] ウィンドウのスクリーンショット。[コースに講師を割り当てる] ビューまたは [コースから削除] ビューが表示されています。

リレーションシップを持つエンティティを既存のエンティティに追加する

Site.Master マスター ページを使用する CoursesAdd.aspx という名前の新しい Web ページを作成し、 という名前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ナビゲーション プロパティを更新します。

マークアップでは、新しいCourseエンティティのDetailsView追加に使用するコントロールも作成されます。 マークアップでは、エンティティ プロパティにバインドされたフィールドが Course 使用されます。 この値はシステムによって生成される ID フィールドではないので、値を入力 CourseID する必要があります。 代わりに、コースの作成時に手動で指定する必要があるコース番号です。

ナビゲーション プロパティはコントロールで使用できないため、 Department ナビゲーション プロパティにはテンプレート フィールドを BoundField 使用します。 テンプレート フィールドには、部門を選択するためのドロップダウン リストが表示されます。 ドロップダウン リストは、 ではなく BindDepartments使用Evalしてエンティティ セットにバインドされます。これは、ナビゲーション プロパティを更新するために直接バインドできないためです。 外部キーを更新する DropDownList コードで使用するコントロール Init への参照を格納できるように、コントロールのイベントのハンドラーを DepartmentID 指定します。

部分クラス宣言の直後の CoursesAdd.aspx.cs で、コントロールへの参照を保持するクラス フィールドを DepartmentsDropDownList 追加します。

private DropDownList departmentDropDownList;

コントロールへの参照を DepartmentsDropDownList 格納できるように、コントロールのイベントの Init ハンドラーを追加します。 これにより、ユーザーが入力した値を取得し、それを使用してエンティティの値をDepartmentIDCourse更新できます。

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 新しいレコードが挿入される前にイベントが発生します。 ハンドラーのコードは、コントロールから をDepartmentIDDropDownList取得し、それを使用してエンティティの プロパティに使用DepartmentIDされる値をCourse設定します。

Entity Framework は、関連付けられたDepartmentエンティティのナビゲーション プロパティにCoursesこのコースを追加します。 また、エンティティのナビゲーション プロパティに Department 部署を Course 追加します。

ページを実行します。

[インターネット エクスプローラー] ウィンドウのスクリーンショット。ID、タイトル、クレジットのテキスト フィールドと [部署] ドロップダウンが表示された [コースの追加] ビューが表示されています。

ID、タイトル、クレジットの数を入力し、部署を選択して、[ 挿入] をクリックします。

Courses.aspx ページを実行し、同じ部署を選択して新しいコースを表示します。

Image03

多対多リレーションシップの操作

エンティティ セットとエンティティ セットの Courses 間の People リレーションシップは、多対多リレーションシップです。 Courseエンティティには、 という名前Peopleのナビゲーション プロパティがあり、0 個、1 つ以上の関連Personエンティティ (そのコースを教えるために割り当てられた講師を表します) を含めることができます。 また、 Person エンティティには という名前 Courses のナビゲーション プロパティがあり、0 個、1 つ以上の関連 Course エンティティ (講師が教えるために割り当てられているコースを表します) を含めることができます。 1 人の講師が複数のコースを教え、1 つのコースが複数の講師によって教えられる場合があります。 チュートリアルのこのセクションでは、関連エンティティのナビゲーション プロパティを更新して、 と Course エンティティの間Personのリレーションシップを追加および削除します。

Site.Master マスター ページを使用する InstructorsCourses.aspx という名前の新しい Web ページを作成し、 という名前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エンティティのPerson名前とPersonIDエンティティを取得するコントロールを作成します。 DropDrownListコントロールはコントロールにEntityDataSourceバインドされます。 コントロールは DropDownList 、イベントのハンドラーを DataBound 指定します。 このハンドラーを使用して、コースを表示する 2 つのドロップダウン リストをデータバインドします。

マークアップでは、選択した講師にコースを割り当てるために使用する次のコントロールのグループも作成されます。

  • DropDownList割り当てるコースを選択するためのコントロール。 このコントロールには、選択した講師に現在割り当てられないコースが設定されます。
  • Button割り当てを開始するコントロール。
  • Label割り当てが失敗した場合にエラー メッセージを表示するコントロール。

最後に、マークアップでは、選択したインストラクターからコースを削除するために使用するコントロールのグループも作成されます。

InstructorsCourses.aspx.cs で、using ステートメントを追加します。

using ContosoUniversity.DAL;

コースを表示する 2 つのドロップダウン リストを設定するためのメソッドを追加します。

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 取得し、選択したインストラクターの Courses エンティティの Person ナビゲーション プロパティからコースを取得します。 次に、その講師に割り当てられているコースを決定し、それに応じてドロップダウン リストを設定します。

ボタン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し、選択したコースを講師のPersonエンティティのナビゲーション プロパティにCourses追加します。 その後、データベースへの変更を保存し、ドロップダウン リストを再入力して、結果をすぐに確認できるようにします。

ボタン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 し、選択したコースを Person エンティティの Courses ナビゲーション プロパティから削除します。 その後、データベースへの変更を保存し、ドロップダウン リストを再入力して、結果をすぐに確認できるようにします。

報告する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();
}

ページを実行します。

[インターネット エクスプローラー] ウィンドウのスクリーンショット。[コースに講師を割り当てる] ビューまたは [コースから削除] ビューに対応するドロップダウンが表示されています。

講師を選択します。 [ コースの割り当て ] ドロップダウン リストには、講師が教えていないコースが表示され、[コースの 削除 ] ドロップダウン リストには、講師が既に割り当てられているコースが表示されます。 [ コースの割り当て ] セクションで、コースを選択し、[ 割り当て] をクリックします。 コースが [コースの 削除 ] ドロップダウン リストに移動します。 [コースの削除] セクションでコースを選択し、[削除] をクリックしますコースが [コースの割り当て] ドロップダウン リストに移動します。

これで、関連データを操作するいくつかの方法が見られました。 次のチュートリアルでは、データ モデルで継承を使用して、アプリケーションの保守性を向上させる方法について説明します。