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] ページに追加します。
EntityDataSource の "Where" プロパティを使用したデータのフィルター処理
前のチュートリアルで作成した [Students.aspx] ページを開きます。 現在構成されているとおり、ページ内の GridView
コントロールには People
エンティティ セットのすべての名前が表示されます。 ただし、登録日が null 以外の Person
エンティティを選択して検索できる学生のみを表示する必要があります。
デザイン ビューに切り替え、EntityDataSource
コントロールを選択します。 [プロパティ] ウィンドウで、 Where
プロパティを it.EnrollmentDate is not null
に設定します。
EntityDataSource
コントロールの Where
プロパティで使用する構文は Entity SQL です。 Entity SQL は Transact-SQL に似ていますが、データベース オブジェクトではなくエンティティで使用するようにカスタマイズされています。 式 it.EnrollmentDate is not null
の単語 it
は、クエリによって返されるエンティティへの参照を表します。 したがって、it.EnrollmentDate
は、EntityDataSource
コントロールが返す Person
エンティティの EnrollmentDate
プロパティを参照します。
このページを実行します。 学生リストに学生のみが含まれるようになりました。 (登録日がない行は表示されません。)
EntityDataSource の "OrderBy" プロパティを使用したデータの並べ替え
このリストを最初に表示するときに、名前順にすることもできます。 [Students.aspx] ページがデザイン ビューで開いたまま、EntityDataSource
コントロールが選択された状態で、[プロパティ] ウィンドウで [OrderBy] プロパティを it.LastName
に設定します。
このページを実行します。 学生リストが姓の順になりました。
コントロール パラメーターを使用した "Where" プロパティの設定
他のデータ ソース コントロールと同様に、パラメーター値を Where
プロパティに渡すことができます。 チュートリアルの第 2 部で作成した [Courses.aspx] ページでは、このメソッドを使用して、ユーザーがドロップダウン リストから選択した部門に関連付けられているコースを表示できます。
[Courses.aspx] を開き、デザイン ビューに切り替えます。 ページに 2 つ目の EntityDataSource
コントロールを追加し、CoursesEntityDataSource
と名前を付けます。 SchoolEntities
モデルに接続し、[EntitySetName] の値として Courses
を選択します。
[プロパティ] ウィンドウで、[Where] プロパティ ボックスの省略記号をクリックします。 ([プロパティ] ウィンドウを使用する前に、CoursesEntityDataSource
コントロールがまだ選択されていることを確認してください。)
[式エディター] ダイアログ ボックスが表示されます。 このダイアログ ボックスで、[指定されたパラメーターに基づいて Where 式を自動的に生成] を選択し、[パラメーターの追加] をクリックします。 パラメーターに DepartmentID
と名前を付け、[パラメーターソース] の値として [Control] を選択し、[ControlID] の値として [DepartmentsDropDownList] を選択します。
[詳細設定プロパティの表示] をクリックし、[式エディター] ダイアログ ボックスの [プロパティ] ウィンドウで、Type
プロパティを Int32
に変更します。
終わったら [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
に設定します。
デザイナーの使用が終わったので、ソース ビューに切り替え、CoursesEntityDataSource
コントロールの ConnectionString
と DefaultContainer
の名前プロパティを 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
コントロールに表示されます。
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
に設定します。
ソース ビューで、ConnectionString
と DefaultContainer
の名前プロパティを 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>
Select
、GroupBy
および 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>
ページを実行して、登録日ごとの学生数を示すリストを表示します。
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
の外部キー列が含まれています。 データベースに直接クエリを実行していた場合、コース データと共に部門名を取得するには、Course
と Department
のテーブルを結合する必要があります。 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
が指定されます。
このページを実行します。 最初の表示には、すべてのコースのリストが部門、次にコース タイトルの順に表示されます。
「m」と入力し、[検索] をクリックすると、タイトルが "m" で始まるすべてのコースが表示されます (検索では大文字と小文字が区別されません)。
"Like" 演算子を使用したデータのフィルター処理
EntityDataSource
コントロールの Where
プロパティの Like
演算子を使用して、QueryExtender
コントロールの StartsWith
、Contains
および 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
パラメーターの既定値が "%" であるため、最初はすべての学生が表示されます。
テキスト ボックスに文字「g」を入力し、[検索] をクリックします。 名または姓に "g" が含まれる学生のリストが表示されます。
これで、個々のテーブルのデータが表示、更新、フィルター処理、並べ替え、そしてグループ化されました。 次のチュートリアルでは、関連するデータ (マスターと詳細のシナリオ) の操作を開始します。