Entity Framework 4.0 Database First と ASP.NET 4 Web Forms の概要 - 第 3 部

著者: Tom Dykstra

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

データのフィルター処理、並べ替え、およびグループ化

前のチュートリアルでは、EntityDataSource コントロールを使用してデータの表示と編集を行いました。 このチュートリアルでは、データのフィルター処理、並べ替え、グループ化を行います。 EntityDataSource コントロールのプロパティを設定してこれを行う場合、構文が他のデータ ソース コントロールとは異なります。 ただし、これから説明するように、QueryExtender コントロールを使用すると、その違いを最小限に抑えることができます。

[Students.aspx] ページを変更して、学生をフィルター処理し、名前で並べ替え、名前で検索します。 また、[Courses.aspx] ページを変更して、選択した部門のコースを表示し、名前でコースを検索します。 最後に、学生の統計情報を [About.aspx] ページに追加します。

Screenshot of the Internet Explorer window, which is showing the Student List view with a table of students.

Screenshot of the Internet Explorer window, which is showing the Courses by Department and Courses by Name views.

Screenshot of the Internet Explorer window, which is showing the Student Body Statistics view with a table of enrollment dates.

Screenshot of the Internet Explorer window, which is showing the Find Students by Name view with the letter g entered into the search query.

EntityDataSource の "Where" プロパティを使用したデータのフィルター処理

前のチュートリアルで作成した [Students.aspx] ページを開きます。 現在構成されているとおり、ページ内の GridView コントロールには People エンティティ セットのすべての名前が表示されます。 ただし、登録日が null 以外の Person エンティティを選択して検索できる学生のみを表示する必要があります。

デザイン ビューに切り替え、EntityDataSource コントロールを選択します。 [プロパティ] ウィンドウで、 Where プロパティを it.EnrollmentDate is not nullに設定します。

Image01

EntityDataSource コントロールの Where プロパティで使用する構文は Entity SQL です。 Entity SQL は Transact-SQL に似ていますが、データベース オブジェクトではなくエンティティで使用するようにカスタマイズされています。 式 it.EnrollmentDate is not null の単語 it は、クエリによって返されるエンティティへの参照を表します。 したがって、it.EnrollmentDate は、EntityDataSource コントロールが返す Person エンティティの EnrollmentDate プロパティを参照します。

このページを実行します。 学生リストに学生のみが含まれるようになりました。 (登録日がない行は表示されません。)

Screenshot of the Internet Explorer window, which shows the Student List view with a table of students.

EntityDataSource の "OrderBy" プロパティを使用したデータの並べ替え

このリストを最初に表示するときに、名前順にすることもできます。 [Students.aspx] ページがデザイン ビューで開いたまま、EntityDataSource コントロールが選択された状態で、[プロパティ] ウィンドウで [OrderBy] プロパティを it.LastName に設定します。

Image05

このページを実行します。 学生リストが姓の順になりました。

Image04

コントロール パラメーターを使用した "Where" プロパティの設定

他のデータ ソース コントロールと同様に、パラメーター値を Where プロパティに渡すことができます。 チュートリアルの第 2 部で作成した [Courses.aspx] ページでは、このメソッドを使用して、ユーザーがドロップダウン リストから選択した部門に関連付けられているコースを表示できます。

[Courses.aspx] を開き、デザイン ビューに切り替えます。 ページに 2 つ目の EntityDataSource コントロールを追加し、CoursesEntityDataSource と名前を付けます。 SchoolEntities モデルに接続し、[EntitySetName] の値として Courses を選択します。

[プロパティ] ウィンドウで、[Where] プロパティ ボックスの省略記号をクリックします。 ([プロパティ] ウィンドウを使用する前に、CoursesEntityDataSource コントロールがまだ選択されていることを確認してください。)

Image06

[式エディター] ダイアログ ボックスが表示されます。 このダイアログ ボックスで、[指定されたパラメーターに基づいて Where 式を自動的に生成] を選択し、[パラメーターの追加] をクリックします。 パラメーターに DepartmentID と名前を付け、[パラメーターソース] の値として [Control] を選択し、[ControlID] の値として [DepartmentsDropDownList] を選択します。

Image07

[詳細設定プロパティの表示] をクリックし、[式エディター] ダイアログ ボックスの [プロパティ] ウィンドウで、Type プロパティを Int32 に変更します。

Image15

終わったら [OK] をクリックします。

ドロップダウン リストの下で、GridView コントロールをページに追加し、CoursesGridView と名前を付けます。 CoursesEntityDataSource データ ソース コントロールに接続し、[スキーマの更新] をクリックし、[列の編集] をクリックして DepartmentID 列を削除します。 GridView コントロール マークアップは、次の例のようになります。

<asp:GridView ID="CoursesGridView" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="CourseID" DataSourceID="CoursesEntityDataSource">
        <Columns>
            <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" />
        </Columns>
    </asp:GridView>

ユーザーがドロップダウン リストで選択した部門を変更したときに、関連付けられているコースのリストが自動的に変更されるようにしたいと思います。 これを行うには、ドロップダウン リストを選択し、[プロパティ] ウィンドウで AutoPostBack プロパティを True に設定します。

Image08

デザイナーの使用が終わったので、ソース ビューに切り替え、CoursesEntityDataSource コントロールの ConnectionStringDefaultContainer の名前プロパティを ContextTypeName="ContosoUniversity.DAL.SchoolEntities" に置き換えます。 完了すると、コントロールのマークアップは次の例のようになります。

<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false"
        EntitySetName="Courses" 
        AutoGenerateWhereClause="true" Where="">
        <WhereParameters>
            <asp:ControlParameter ControlID="DepartmentsDropDownList" Type="Int32" 
                Name="DepartmentID" PropertyName="SelectedValue" />
        </WhereParameters>
    </asp:EntityDataSource>

ページを実行し、ドロップダウン リストを使用して異なる部門を選択します。 選択した部門ごとに提供されるコースのみが GridView コントロールに表示されます。

Image09

EntityDataSource の "GroupBy" プロパティを使用したデータのグループ化

Contoso University が、[バージョン情報] ページに全学生の統計情報を配置したいとします。 具体的には、登録日ごとに学生数の内訳を表示する必要があります。

[About.aspx] を開き、ソース ビューで、BodyContent コントロールの既存の内容を h2 タグに挟まれた "Student Body Statistics" に置き換えます。

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>Student Body Statistics</h2>
</asp:Content>

見出しの後に EntityDataSource コントロールを追加し、StudentStatisticsEntityDataSource と名前を付けます。 SchoolEntities に接続し、People エンティティ セットを選択し、ウィザードの [選択] ボックスを変更せずに残します。 [プロパティ] ウィンドウで、次のプロパティを設定します。

  • 学生のみをフィルター処理するには、Where プロパティを it.EnrollmentDate is not null に設定します。
  • 登録日ごとに結果をグループ化するには、GroupBy プロパティを it.EnrollmentDate に設定します。
  • 登録日と学生の数を選択するには、Select プロパティを it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents に設定します。
  • 登録日ごとに結果を並べ替えるには、OrderBy プロパティを it.EnrollmentDate に設定します。

ソース ビューで、ConnectionStringDefaultContainer の名前プロパティを ContextTypeName に置き換えます。 EntityDataSource コントロール マークアップが、次の例のようになりました。

<asp:EntityDataSource ID="StudentStatisticsEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="People"
        Select="it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents" 
        OrderBy="it.EnrollmentDate" GroupBy="it.EnrollmentDate"
        Where="it.EnrollmentDate is not null" >
    </asp:EntityDataSource>

SelectGroupBy および Where のプロパティの構文は、現在のエンティティを指定する it キーワードを除き、Transact-SQL に似ています。

次のマークアップを追加して、データを表示する GridView コントロールを作成します。

<asp:GridView ID="StudentStatisticsGridView" runat="server" AutoGenerateColumns="False" 
        DataSourceID="StudentStatisticsEntityDataSource">
        <Columns>
            <asp:BoundField DataField="EnrollmentDate" DataFormatString="{0:d}" 
                HeaderText="Date of Enrollment" 
                ReadOnly="True" SortExpression="EnrollmentDate" />
            <asp:BoundField DataField="NumberOfStudents" HeaderText="Students" 
                ReadOnly="True" SortExpression="NumberOfStudents" />
        </Columns>
    </asp:GridView>

ページを実行して、登録日ごとの学生数を示すリストを表示します。

Screenshot of the Internet Explorer window, which shows the Student Body Statistics view with a table of enrollment dates.

QueryExtender コントロールを使用したフィルター処理と並べ替え

QueryExtender コントロールを使用すると、マークアップでフィルター処理と並べ替えを指定することができます。 この構文は、使用しているデータベース管理システム (DBMS) に依存しません。 また、通常は Entity Framework からも独立しています。ただし、ナビゲーション プロパティに使用する構文が Entity Framework に固有である点が異なります。

チュートリアルのこの部分では、QueryExtender コントロールを使用してデータのフィルター処理と並べ替えを行い、並べ替えフィールドの 1 つがナビゲーション プロパティになります。

(マークアップではなくコードを使用して、EntityDataSource コントロールによって自動的に生成されるクエリを拡張する場合は、QueryCreated イベントを処理することでこれを行うことができます。この方法で、QueryExtender コントロールが EntityDataSource 制御クエリにも拡張されます。)

[Courses.aspx] ページを開き、前に追加したマークアップの下に次のマークアップを挿入して、見出し、検索文字列を入力するためのテキスト ボックス、検索ボタン、Courses エンティティ セットにバインドされる EntityDataSource コントロールを作成します。

<h2>Courses by Name</h2>
    Enter a course name 
    <asp:TextBox ID="SearchTextBox" runat="server"></asp:TextBox>
     <asp:Button ID="SearchButton" runat="server" Text="Search" />
    <br /><br />
    <asp:EntityDataSource ID="SearchEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="Courses"  
        Include="Department" >
    </asp:EntityDataSource>

EntityDataSource コントロールの Include プロパティが Department に設定されていることを確認してください。 このデータベースでは、Course テーブルに部門名が含まれていません。DepartmentID の外部キー列が含まれています。 データベースに直接クエリを実行していた場合、コース データと共に部門名を取得するには、CourseDepartment のテーブルを結合する必要があります。 Include プロパティを Department に設定すると、Course エンティティを取得するときに、Entity Framework が関連する Department エンティティを取得する処理を実行するように指定されます。 その後、Department エンティティは Course エンティティの Department ナビゲーション プロパティに格納されます。 (既定では、データ モデル デザイナーによって生成された SchoolEntities クラスが、必要に応じて関連データを取得し、データ ソース コントロールをそのクラスにバインドしているため、Include プロパティを設定する必要はありません。ただし、これを設定すると、ページのパフォーマンスが向上します。これを行わないと、Entity Framework がデータベースを個別に呼び出して、Course エンティティと、関連する Department エンティティのデータを取得するためです。)

先ほど作成した EntityDataSource コントロールの後に、次のマークアップを挿入して、その EntityDataSource コントロールにバインドされる QueryExtender コントロールを作成します。

<asp:QueryExtender ID="SearchQueryExtender" runat="server" 
        TargetControlID="SearchEntityDataSource" >
        <asp:SearchExpression SearchType="StartsWith" DataFields="Title">
            <asp:ControlParameter ControlID="SearchTextBox" />
        </asp:SearchExpression>
        <asp:OrderByExpression DataField="Department.Name" Direction="Ascending">
            <asp:ThenBy DataField="Title" Direction="Ascending" />            
        </asp:OrderByExpression>
    </asp:QueryExtender>

SearchExpression 要素によって、タイトルがテキスト ボックスに入力された値と一致するコースを選択するように指定されます。 SearchType プロパティが StartsWith を指定しているため、テキスト ボックスに入力された文字数のみが比較されます。

OrderByExpression 要素によって、結果セットが部門名内のコース タイトルによって並べ替えられるように指定されます。 Department.Name のように部門名が指定されていることを確認してください。 Course エンティティと Department エンティティの間の関連付けは 1 対 1 であるため、Department ナビゲーション プロパティには Department エンティティが含まれます。 (これが 1 対多の関係である場合、プロパティにはコレクションが含まれます。)部門名を取得するには、Department エンティティの Name プロパティを指定する必要があります。

最後に、コースのリストを表示する GridView コントロールを追加します。

<asp:GridView ID="SearchGridView" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="CourseID" DataSourceID="SearchEntityDataSource"  AllowPaging="true">
        <Columns>
            <asp:TemplateField HeaderText="Department">
                <ItemTemplate>
                    <asp:Label ID="Label2" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="CourseID" HeaderText="ID"/>
            <asp:BoundField DataField="Title" HeaderText="Title" />
            <asp:BoundField DataField="Credits" HeaderText="Credits" />
        </Columns>
    </asp:GridView>

最初の列は、部門名を表示するテンプレート フィールドです。 データ バインド式では、QueryExtender コントロールで見たのと同様に、Department.Name が指定されます。

このページを実行します。 最初の表示には、すべてのコースのリストが部門、次にコース タイトルの順に表示されます。

Screenshot of the Internet Explorer window, which shows the Courses by Department and Courses by Name views.

「m」と入力し、[検索] をクリックすると、タイトルが "m" で始まるすべてのコースが表示されます (検索では大文字と小文字が区別されません)。

Image12

"Like" 演算子を使用したデータのフィルター処理

EntityDataSource コントロールの Where プロパティの Like 演算子を使用して、QueryExtender コントロールの StartsWithContains および EndsWith の検索の種類と同様の効果を得ることができます。 チュートリアルのこの部分では、Like 演算子を使用して学生を名前で検索する方法について説明します。

ソース ビューで、[Students.aspx] を開きます。 GridView コントロールの後に、次のマークアップを追加します。

<h2>Find Students by Name</h2>
    Enter any part of the name
    <asp:TextBox ID="SearchTextBox" runat="server" AutoPostBack="true"></asp:TextBox>
     <asp:Button ID="SearchButton" runat="server" Text="Search" />
    <br />
    <br />
    <asp:EntityDataSource ID="SearchEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="People"
        Where="it.EnrollmentDate is not null and (it.FirstMidName Like '%' + @StudentName + '%' or it.LastName Like '%' + @StudentName + '%')" >
        <WhereParameters>
            <asp:ControlParameter ControlID="SearchTextBox" Name="StudentName" PropertyName="Text" 
             Type="String" DefaultValue="%"/>
        </WhereParameters>
    </asp:EntityDataSource>
    <asp:GridView ID="SearchGridView" runat="server" AutoGenerateColumns="False" DataKeyNames="PersonID"
        DataSourceID="SearchEntityDataSource" AllowPaging="true">
        <Columns>
            <asp:TemplateField HeaderText="Name" SortExpression="LastName, FirstMidName">
                <ItemTemplate>
                    <asp:Label ID="LastNameFoundLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>, 
                    <asp:Label ID="FirstNameFoundLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
                <ItemTemplate>
                    <asp:Label ID="EnrollmentDateFoundLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

このマークアップは、Where プロパティ値を除き、前に説明したものと似ています。 Where 式の 2 番目の部分では、テキスト ボックスに入力されたものについて、姓と名の両方を検索する substring 検索 (LIKE %FirstMidName% or LIKE %LastName%) を定義します。

このページを実行します。 StudentName パラメーターの既定値が "%" であるため、最初はすべての学生が表示されます。

Image13

テキスト ボックスに文字「g」を入力し、[検索] をクリックします。 名または姓に "g" が含まれる学生のリストが表示されます。

Screenshot of the Internet Explorer window, which shows the Find Students by Name view with the letter g entered into the search query.

これで、個々のテーブルのデータが表示、更新、フィルター処理、並べ替え、そしてグループ化されました。 次のチュートリアルでは、関連するデータ (マスターと詳細のシナリオ) の操作を開始します。