次の方法で共有


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

作成者: Tom Dykstra

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

前のチュートリアルでは、 コントロールを使用してデータの EntityDataSource フィルター処理、並べ替え、グループ化を行いました。 このチュートリアルでは、関連データを表示および更新します。

講師の一覧を表示する [講師] ページを作成します。 インストラクターを選択すると、そのインストラクターによって教えられたコースの一覧が表示されます。 コースを選択すると、コースの詳細と、コースに登録されている学生の一覧が表示されます。 講師名、採用日、およびオフィスの割り当てを編集できます。 Office の割り当ては、ナビゲーション プロパティを介してアクセスする個別のエンティティ セットです。

マスター データは、マークアップまたはコード内の詳細データにリンクできます。 チュートリアルのこの部分では、両方の方法を使用します。

Image01

Site.Master マスター ページを使用する Instructors.aspx という名前の新しい Web ページを作成し、 という名前Content2のコントロールに次のマークアップをContent追加します。

<h2>Instructors</h2>
    <div>
        <asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" 
            ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
            EntitySetName="People"
            Where="it.HireDate is not null" Include="OfficeAssignment" EnableUpdate="True">
        </asp:EntityDataSource>
    </div>

このマークアップにより、講師を EntityDataSource 選択して更新を有効にするコントロールが作成されます。 要素は div 、後で右側に列を追加できるように、左側にレンダリングするようにマークアップを構成します。

マークアップと終了タグのEntityDataSource間に、エラー メッセージに使用するコントロールとLabelコントロールをGridView作成する次のマークアップを追加</div>します。

<asp:GridView ID="InstructorsGridView" runat="server" AllowPaging="True" AllowSorting="True"
            AutoGenerateColumns="False" DataKeyNames="PersonID" DataSourceID="InstructorsEntityDataSource"
            OnSelectedIndexChanged="InstructorsGridView_SelectedIndexChanged" 
            SelectedRowStyle-BackColor="LightGray" 
            onrowupdating="InstructorsGridView_RowUpdating">
            <Columns>
                <asp:CommandField ShowSelectButton="True" ShowEditButton="True" />
                <asp:TemplateField HeaderText="Name" SortExpression="LastName">
                    <ItemTemplate>
                        <asp:Label ID="InstructorLastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
                        <asp:Label ID="InstructorFirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="InstructorLastNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>' Width="7em"></asp:TextBox>
                        <asp:TextBox ID="InstructorFirstNameTextBox" runat="server" Text='<%# Bind("LastName") %>' Width="7em"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Hire Date" SortExpression="HireDate">
                    <ItemTemplate>
                        <asp:Label ID="InstructorHireDateLabel" runat="server" Text='<%# Eval("HireDate", "{0:d}") %>'></asp:Label>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="InstructorHireDateTextBox" runat="server" Text='<%# Bind("HireDate", "{0:d}") %>' Width="7em"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Office Assignment" SortExpression="OfficeAssignment.Location">
                    <ItemTemplate>
                        <asp:Label ID="InstructorOfficeLabel" runat="server" Text='<%# Eval("OfficeAssignment.Location") %>'></asp:Label>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="InstructorOfficeTextBox" runat="server" 
                        Text='<%# Eval("OfficeAssignment.Location") %>' Width="7em"
                        oninit="InstructorOfficeTextBox_Init"></asp:TextBox>
                    </EditItemTemplate>
                </asp:TemplateField>
            </Columns>
            <SelectedRowStyle BackColor="LightGray"></SelectedRowStyle>
        </asp:GridView>
        <asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false" ViewStateMode="Disabled"></asp:Label>

このGridViewコントロールは、行の選択を有効にし、選択した行を薄い灰色の背景色で強調表示し、 イベントと Updating イベントのハンドラー (後で作成します) をSelectedIndexChanged指定します。 また、選択した行のキー値を後で追加する別のコントロールに渡すことができるように、 プロパティにも を指定PersonIDDataKeyNamesします。

最後の列には講師のオフィスの割り当てが含まれています。これは、関連付けられたエンティティから取得されるため、エンティティの Person ナビゲーション プロパティに格納されます。 コントロールをEditItemTemplate更新するためにナビゲーション プロパティにGridView直接バインドできないため、 要素は の代わりに Bindを指定Evalしていることに注意してください。 コードで Office の割り当てを更新します。 これを行うには、コントロールへの参照がTextBox必要です。コントロールのイベントにTextBoxInitこれを取得して保存します。

次の GridView コントロールは、 Label エラー メッセージに使用されるコントロールです。 コントロールの Visible プロパティは で false、ビューステートはオフになっているため、エラーに応答してコードによって表示される場合にのみラベルが表示されます。

Instructors.aspx.cs ファイルを開き、次usingのステートメントを追加します。

using ContosoUniversity.DAL;

部分クラス名宣言の直後にプライベート クラス フィールドを追加して、office の割り当てテキスト ボックスへの参照を保持します。

private TextBox instructorOfficeTextBox;

後でコードを追加する SelectedIndexChanged イベント ハンドラーのスタブを追加します。 また、コントロールへの参照を格納できるように、Office 割り当て TextBox コントロールの Init イベントのハンドラーを TextBox 追加します。 この参照を使用して、ナビゲーション プロパティに関連付けられているエンティティを更新するためにユーザーが入力した値を取得します。

protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}

protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
    instructorOfficeTextBox = sender as TextBox;
}

コントロールUpdatingの イベントをGridView使用して、関連付けられているOfficeAssignmentエンティティの プロパティを更新Locationします。 イベントに次のハンドラーを Updating 追加します。

protected void InstructorsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    using (var context = new SchoolEntities())
    {
        var instructorBeingUpdated = Convert.ToInt32(e.Keys[0]);
        var officeAssignment = (from o in context.OfficeAssignments
                                where o.InstructorID == instructorBeingUpdated
                                select o).FirstOrDefault();

        try
        {
            if (String.IsNullOrWhiteSpace(instructorOfficeTextBox.Text) == false)
            {
                if (officeAssignment == null)
                {
                    context.OfficeAssignments.AddObject(OfficeAssignment.CreateOfficeAssignment(instructorBeingUpdated, instructorOfficeTextBox.Text, null));
                }
                else
                {
                    officeAssignment.Location = instructorOfficeTextBox.Text;
                }
            }
            else
            {
                if (officeAssignment != null)
                {
                    context.DeleteObject(officeAssignment);
                }
            }
            context.SaveChanges();
        }
        catch (Exception)
        {
            e.Cancel = true;
            ErrorMessageLabel.Visible = true;
            ErrorMessageLabel.Text = "Update failed.";
            //Add code to log the error.
        }
    }
}

このコードは、ユーザーが行の [更新GridView] をクリックしたときに実行されます。 このコードでは、LINQ to Entitiesを使用して、イベント引数から選択した行の をPersonID使用して、現在Personのエンティティに関連付けられているエンティティを取得OfficeAssignmentします。

次に、コードはコントロールの値に応じて、次のいずれかのアクションを InstructorOfficeTextBox 実行します。

  • テキスト ボックスに値があり、更新するエンティティがない OfficeAssignment 場合は、その値が作成されます。
  • テキスト ボックスに値があり、エンティティがある場合は OfficeAssignment 、プロパティ値が更新されます Location
  • テキスト ボックスが空でエンティティが存在する OfficeAssignment 場合は、エンティティが削除されます。

その後、変更がデータベースに保存されます。 例外が発生すると、エラー メッセージが表示されます。

ページを実行します。

Image02

[ 編集] をクリックすると、すべてのフィールドがテキスト ボックスに変わります。

Image03

Office の割り当てを含め、これらの値のいずれかを変更します。 [ 更新 ] をクリックすると、変更が一覧に反映されます。

各講師は 1 つ以上のコースを教えることができるので、コントロールとコントロールをEntityDataSourceGridView追加して、インストラクター GridView コントロールで選択されている講師に関連付けられているコースを一覧表示します。 コース エンティティの見出しとコントロールを EntityDataSource 作成するには、エラー メッセージ Label コントロールと終了 </div> タグの間に次のマークアップを追加します。

<h3>Courses Taught</h3>
        <asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" 
            ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
            EntitySetName="Courses" 
            Where="@PersonID IN (SELECT VALUE instructor.PersonID FROM it.People AS instructor)">
            <WhereParameters>
                <asp:ControlParameter ControlID="InstructorsGridView" Type="Int32" Name="PersonID" PropertyName="SelectedValue" />
            </WhereParameters>
        </asp:EntityDataSource>

パラメーターには Where 、コントロールで行が PersonID 選択されている講師の の値が InstructorsGridView 含まれます。 プロパティにはWhere、エンティティPeopleのナビゲーション プロパティからCourseすべての関連付けられたエンティティを取得し、関連付けられているPersonエンティティの 1 つにPerson選択されたPersonID値が含まれている場合にのみエンティティを選択Courseするサブセレクト コマンドが含まれています。

コントロールをGridView作成するには、コントロールの直後 (終了</div>タグのCoursesEntityDataSource前) に次のマークアップを追加します。

<asp:GridView ID="CoursesGridView" runat="server" 
            DataSourceID="CoursesEntityDataSource"
            AllowSorting="True" AutoGenerateColumns="False"
            SelectedRowStyle-BackColor="LightGray" 
            DataKeyNames="CourseID">
            <EmptyDataTemplate>
                <p>No courses found.</p>
            </EmptyDataTemplate>
            <Columns>
                <asp:CommandField ShowSelectButton="True" />
                <asp:BoundField DataField="CourseID" HeaderText="ID" ReadOnly="True" SortExpression="CourseID" />
                <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
                <asp:TemplateField HeaderText="Department" SortExpression="DepartmentID">
                    <ItemTemplate>
                        <asp:Label ID="GridViewDepartmentLabel" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>

講師が選択されていない場合、コースは表示されないため、 EmptyDataTemplate 要素が含まれます。

ページを実行します。

Image04

1 つ以上のコースが割り当てられている講師を選択し、コースまたはコースが一覧に表示されます。 (注: データベース スキーマでは複数のコースが許可されますが、データベースで提供されるテスト データでは、インストラクターが実際に複数のコースを持つ必要はありません。[Server エクスプローラー] ウィンドウまたは CoursesAdd.aspx ページを使用して、データベースにコースを自分で追加できます。このページは、後のチュートリアルで追加します)。

Image05

コントロールには CoursesGridView 、少数のコース フィールドのみが表示されます。 コースのすべての詳細を表示するには、ユーザーが選択した DetailsView コースのコントロールを使用します。 Instructors.aspx で、終了</div>タグの後に次のマークアップを追加します (このマークアップは、その前ではなく、終了 div タグのに配置してください)。

<div>
        <h3>Course Details</h3>
        <asp:EntityDataSource ID="CourseDetailsEntityDataSource" runat="server" 
            ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
            EntitySetName="Courses"
            AutoGenerateWhereClause="False" Where="it.CourseID = @CourseID" Include="Department,OnlineCourse,OnsiteCourse,StudentGrades.Person"
            OnSelected="CourseDetailsEntityDataSource_Selected">
            <WhereParameters>
                <asp:ControlParameter ControlID="CoursesGridView" Type="Int32" Name="CourseID" PropertyName="SelectedValue" />
            </WhereParameters>
        </asp:EntityDataSource>
        <asp:DetailsView ID="CourseDetailsView" runat="server" AutoGenerateRows="False"
            DataSourceID="CourseDetailsEntityDataSource">
            <EmptyDataTemplate>
                <p>
                    No course selected.</p>
            </EmptyDataTemplate>
            <Fields>
                <asp:BoundField DataField="CourseID" HeaderText="ID" ReadOnly="True" SortExpression="CourseID" />
                <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
                <asp:BoundField DataField="Credits" HeaderText="Credits" SortExpression="Credits" />
                <asp:TemplateField HeaderText="Department">
                    <ItemTemplate>
                        <asp:Label ID="DetailsViewDepartmentLabel" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Location">
                    <ItemTemplate>
                        <asp:Label ID="LocationLabel" runat="server" Text='<%# Eval("OnsiteCourse.Location") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="URL">
                    <ItemTemplate>
                        <asp:Label ID="URLLabel" runat="server" Text='<%# Eval("OnlineCourse.URL") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
            </Fields>
        </asp:DetailsView>
    </div>

このマークアップは、 EntityDataSource エンティティ セットにバインドされたコントロールを Courses 作成します。 プロパティは Where 、courses コントロールで選択した行の値を使用して CourseID コースを GridView 選択します。 マークアップは、後で学生の成績を Selected 表示するために使用するイベントのハンドラーを指定します。これは、階層内のもう 1 つのレベル低いレベルです。

Instructors.aspx.cs で、 メソッドの次のスタブをCourseDetailsEntityDataSource_Selected作成します。 (このスタブはチュートリアルの後半で入力します。ここでは、ページがコンパイルされて実行されるように、このスタブが必要です)。

protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}

ページを実行します。

Image06

コースが選択されていないため、最初はコースの詳細はありません。 コースが割り当てられている講師を選択し、コースを選択して詳細を表示します。

Image07

最後に、選択したコースに登録されているすべての学生とその成績を表示します。 これを行うには、コース DetailsViewSelectedバインドされたコントロールの EntityDataSource イベントを使用します。

Instructors.aspx で、 コントロールの後に次のマークアップをDetailsView追加します。

<h3>Student Grades</h3>
        <asp:ListView ID="GradesListView" runat="server">
            <EmptyDataTemplate>
                <p>No student grades found.</p>
            </EmptyDataTemplate>
            <LayoutTemplate>
                <table border="1" runat="server" id="itemPlaceholderContainer">
                    <tr runat="server">
                        <th runat="server">
                            Name
                        </th>
                        <th runat="server">
                            Grade
                        </th>
                    </tr>
                    <tr id="itemPlaceholder" runat="server">
                    </tr>
                </table>
            </LayoutTemplate>
            <ItemTemplate>
                <tr>
                    <td>
                        <asp:Label ID="StudentLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>' />,
                        <asp:Label ID="StudentFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>' />
                    </td>
                    <td>
                        <asp:Label ID="StudentGradeLabel" runat="server" Text='<%# Eval("Grade") %>' />
                    </td>
                </tr>
            </ItemTemplate>
        </asp:ListView>

このマークアップにより、 ListView 選択したコースの学生とその成績の一覧を表示するコントロールが作成されます。 コードでコントロールをデータバインドするため、データ ソースは指定されません。 要素は EmptyDataTemplate 、コースが選択されていないときに表示するメッセージを提供します。その場合、表示する学生はいません。 要素は LayoutTemplate 、リストを表示する HTML テーブルを作成し、 で ItemTemplate 表示する列を指定します。 学生 ID と学生の成績はエンティティからStudentGrade取得され、学生名はエンティティのPersonナビゲーション プロパティStudentGradePerson Entity Framework が使用できるエンティティからの名前です。

Instructors.aspx.cs で、stubbed-out CourseDetailsEntityDataSource_Selected メソッドを次のコードに置き換えます。

protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
    var course = e.Results.Cast<Course>().FirstOrDefault();
    if (course != null)
    {
        var studentGrades = course.StudentGrades.ToList();
        GradesListView.DataSource = studentGrades;
        GradesListView.DataBind();
    }
}

このイベントのイベント引数は、選択したデータをコレクションの形式で提供します。何も選択されていない場合は項目が 0、エンティティが選択されている場合 Course は 1 つの項目が含まれます。 エンティティが Course 選択されている場合、コードは メソッドを First 使用してコレクションを 1 つのオブジェクトに変換します。 その後、ナビゲーション プロパティからエンティティを取得 StudentGrade し、それらをコレクションに変換し、コントロールを GradesListView コレクションにバインドします。

これは成績を表示するのに十分ですが、空のデータ テンプレート内のメッセージが、ページが初めて表示されたとき、およびコースが選択されていないときに必ず表示されるようにする必要があります。 これを行うには、次のメソッドを作成します。このメソッドは、2 つの場所から呼び出します。

private void ClearStudentGradesDataSource()
{
    var emptyStudentGradesList = new List<StudentGrade>();
    GradesListView.DataSource = emptyStudentGradesList;
    GradesListView.DataBind();
}

この新しいメソッドを Page_Load メソッドから呼び出して、ページが初めて表示されるときに空のデータ テンプレートを表示します。 また、インストラクターが選択されるとイベントが発生するため、 メソッドから InstructorsGridView_SelectedIndexChanged 呼び出します。つまり、新しいコースがコース GridView コントロールに読み込まれ、まだ選択されていません。 2 つの呼び出しを次に示します。

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        ClearStudentGradesDataSource();                
    }
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
    ClearStudentGradesDataSource();
}

ページを実行します。

Image08

コースが割り当てられている講師を選択し、コースを選択します。

Image09

これで、関連データを操作するいくつかの方法を確認しました。 次のチュートリアルでは、既存のエンティティ間にリレーションシップを追加する方法、リレーションシップを削除する方法、既存のエンティティにリレーションシップを持つ新しいエンティティを追加する方法について説明します。