Entity Framework 4.0 と ObjectDataSource コントロールの使用、パート 3: 並べ替えとフィルター処理
著者: Tom Dykstra
このチュートリアル シリーズは、Entity Framework 4.0 の概要チュートリアル シリーズで作成された Contoso University Web アプリケーションをベースとしています。 前のチュートリアルを終わらせていない場合は、このチュートリアルの始めに、前のチュートリアルで作成するはずであったアプリケーションをダウンロードできます。 完了したチュートリアル シリーズで作成されたアプリケーションをダウンロードすることもできます。 チュートリアルに関する質問がある場合は、ASP.NET Entity Framework フォーラムに質問を投稿できます。
前のチュートリアルでは、Entity Framework と ObjectDataSource
コントロールを使用する n 層 Web アプリケーションにリポジトリ パターンを実装しました。 このチュートリアルでは、並べ替えとフィルター処理を行い、マスター詳細シナリオを処理する方法について説明します。 Departments.aspx ページに次の機能強化を追加します。
- ユーザーが名前で部門を選択できるテキスト ボックス。
- グリッドに表示される各部門向けのコースのリスト。
- 列見出しをクリックして並べ替える機能。
GridView 列を並べ替える機能の追加
Departments.aspx ページを開き、DepartmentsObjectDataSource
という名前の ObjectDataSource
コントロールに SortParameterName="sortExpression"
属性を追加します。 (後で、sortExpression
というパラメーターを受け取る GetDepartments
メソッドを作成します。)コントロールの開始タグのマークアップは、次の例のようになります。
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.BLL.SchoolBL" DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment" UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues" OldValuesParameterFormatString="orig{0}"
OnUpdated="DepartmentsObjectDataSource_Updated" SortParameterName="sortExpression" >
GridView
コントロールの開始タグに AllowSorting="true"
属性を追加します。 コントロールの開始タグのマークアップは、次の例のようになります。
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
OnRowUpdating="DepartmentsGridView_RowUpdating"
AllowSorting="true" >
Departments.aspx.cs で、Page_Load
メソッドから GridView
コントロールの Sort
メソッドを呼び出して、既定の並べ替え順序を設定します。
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DepartmentsGridView.Sort("Name", SortDirection.Ascending);
}
}
ビジネス ロジック クラスまたはリポジトリ クラスで並べ替えまたはフィルター処理を行うコードを追加できます。 ビジネス ロジック クラスで行う場合、並べ替えまたはフィルター処理は、データがデータベースから取得された後に行われます。ビジネス ロジック クラスはリポジトリから返された IEnumerable
オブジェクトを操作するためです。 リポジトリ クラスに並べ替えとフィルター処理のコードを追加し、LINQ 式またはオブジェクト クエリが IEnumerable
オブジェクトに変換される前に行うと、コマンドはデータベースに渡されて処理されます。通常はこの方がより効率的です。 このチュートリアルでは、データベース (つまりリポジトリ) で処理が行われるように並べ替えとフィルター処理を実装します。
並べ替え機能を追加するには、リポジトリ インターフェイスとリポジトリ クラスおよびビジネス ロジック クラスに新しいメソッドを追加する必要があります。 ISchoolRepository.cs ファイルに新しい GetDepartments
メソッドを追加します。これは、返された部門のリストの並べ替えに使用される sortExpression
パラメーターを受け取ります。
IEnumerable<Department> GetDepartments(string sortExpression);
sortExpression
パラメーターは、並べ替える列と並べ替えの方向を指定します。
SchoolRepository.cs ファイルに新しいメソッドのコードを追加します。
public IEnumerable<Department> GetDepartments(string sortExpression)
{
if (String.IsNullOrWhiteSpace(sortExpression))
{
sortExpression = "Name";
}
return context.Departments.Include("Person").OrderBy("it." + sortExpression).ToList();
}
既存のパラメーターなしの GetDepartments
メソッドを、新しいメソッドを呼び出すように変更します。
public IEnumerable<Department> GetDepartments()
{
return GetDepartments("");
}
テスト プロジェクトで、次の新しいメソッドを MockSchoolRepository.cs に追加します。
public IEnumerable<Department> GetDepartments(string sortExpression)
{
return departments;
}
このメソッドで並べ替えられたリストが返されることに依存する単体テストを作成する場合は、リストを返す前に並べ替える必要があります。 このチュートリアルではこのようなテストを作成しないため、このメソッドは、並べ替えられていない部門のリストを返すだけです。
SchoolBL.cs ファイルで、次の新しいメソッドをビジネス ロジック クラスに追加します。
public IEnumerable<Department> GetDepartments(string sortExpression)
{
return schoolRepository.GetDepartments(sortExpression);
}
このコードは、並べ替えパラメーターをリポジトリ メソッドに渡します。
Departments.aspx ページを実行します。
列見出しをクリックすると、その列で並べ替えることができます。 列が既に並べ替えられている場合は、見出しをクリックすると並べ替えの方向が逆になります。
検索ボックスの追加
このセクションでは、検索テキスト ボックスを追加し、コントロール パラメーターを使用して ObjectDataSource
コントロールにリンクし、フィルター処理をサポートするメソッドをビジネス ロジック クラスに追加します。
Departments.aspx ページを開き、見出しと最初の ObjectDataSource
コントロールの間に次のマークアップを追加します。
Enter any part of the name or leave the box blank to see all names:
<asp:TextBox ID="SearchTextBox" runat="server" AutoPostBack="true"></asp:TextBox>
<asp:Button ID="SearchButton" runat="server" Text="Search" />
DepartmentsObjectDataSource
という名前の ObjectDataSource
コントロールで、次の操作を行います。
SearchTextBox
コントロールに入力された値を取得するnameSearchString
という名前のパラメーターのSelectParameters
要素を追加します。SelectMethod
属性の値をGetDepartmentsByName
に変更します。 (このメソッドは後で作成します。)
ObjectDataSource
コントロールのマークアップは、次の例のようになります。
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" TypeName="ContosoUniversity.BLL.SchoolBL"
SelectMethod="GetDepartmentsByName" DeleteMethod="DeleteDepartment" UpdateMethod="UpdateDepartment"
DataObjectTypeName="ContosoUniversity.DAL.Department" ConflictDetection="CompareAllValues"
SortParameterName="sortExpression" OldValuesParameterFormatString="orig{0}"
OnUpdated="DepartmentsObjectDataSource_Updated">
<SelectParameters>
<asp:ControlParameter ControlID="SearchTextBox" Name="nameSearchString" PropertyName="Text"
Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
ISchoolRepository.cs に GetDepartmentsByName
メソッドを追加します。これは、sortExpression
と nameSearchString
の両方のパラメーターを受け取ります。
IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString);
SchoolRepository.cs に、次の新しいメソッドを追加します。
public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
if (String.IsNullOrWhiteSpace(sortExpression))
{
sortExpression = "Name";
}
if (String.IsNullOrWhiteSpace(nameSearchString))
{
nameSearchString = "";
}
return context.Departments.Include("Person").OrderBy("it." + sortExpression).Where(d => d.Name.Contains(nameSearchString)).ToList();
}
このコードでは、Where
メソッドを使用して、検索文字列を含む項目を選択します。 検索文字列が空の場合は、すべてのレコードが選択されます。 1 つのステートメントで複数のメソッド呼び出しを一緒に指定する場合 (Include
の次に OrderBy
、その次に Where
のように)、Where
メソッドは常に最後である必要があることに注意してください。
sortExpression
パラメーターを受け取る既存の GetDepartments
メソッドを、新しいメソッドを呼び出すように変更します。
public IEnumerable<Department> GetDepartments(string sortExpression)
{
return GetDepartmentsByName(sortExpression, "");
}
テスト プロジェクトの MockSchoolRepository.cs で、次の新しいメソッドを追加します。
public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
return departments;
}
SchoolBL.cs で、次の新しいメソッドを追加します。
public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
return schoolRepository.GetDepartmentsByName(sortExpression, nameSearchString);
}
Departments.aspx ページを実行し、検索文字列を入力して、選択ロジックが機能することを確認します。 テキスト ボックスを空のままにし、検索を試して、すべてのレコードが返されることを確認します。
各グリッド行の詳細列の追加
次に、グリッドの右側のセルに表示される各部門向けのすべてのコースを表示します。 これを行うには、入れ子になった GridView
コントロールを使用し、Department
エンティティの Courses
ナビゲーション プロパティのデータにデータバインドします。
Departments.aspx を開き、GridView
コントロールのマークアップで、RowDataBound
イベントのハンドラーを指定します。 コントロールの開始タグのマークアップは、次の例のようになります。
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
OnRowUpdating="DepartmentsGridView_RowUpdating"
OnRowDataBound="DepartmentsGridView_RowDataBound"
AllowSorting="True" >
Administrator
テンプレート フィールドの後に新しい TemplateField
要素を追加します。
<asp:TemplateField HeaderText="Courses">
<ItemTemplate>
<asp:GridView ID="CoursesGridView" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="CourseID" HeaderText="ID" />
<asp:BoundField DataField="Title" HeaderText="Title" />
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
このマークアップは、コースのリストのコース番号とタイトルを示す、入れ子になった GridView
コントロールを作成します。 RowDataBound
ハンドラーのコードでデータバインドを行うため、データ ソースは指定されません。
Departments.aspx.cs を開き、RowDataBound
イベントに対する次のハンドラーを追加します。
protected void DepartmentsGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var department = e.Row.DataItem as Department;
var coursesGridView = (GridView)e.Row.FindControl("CoursesGridView");
coursesGridView.DataSource = department.Courses.ToList();
coursesGridView.DataBind();
}
}
このコードは、イベント引数から Department
エンティティを取得し、Courses
ナビゲーション プロパティを List
コレクションに変換して、入れ子になった GridView
をコレクションにデータバインドします。
SchoolRepository.cs ファイルを開き、GetDepartmentsByName
メソッドで作成したオブジェクト クエリで Include
メソッドを呼び出して、Courses
ナビゲーション プロパティの一括読み込みを指定します。 GetDepartmentsByName
メソッドの return
ステートメントは、次の例のようになります。
return context.Departments.Include("Person").Include("Courses").
OrderBy("it." + sortExpression).Where(d => d.Name.Contains(nameSearchString)).ToList();
このページを実行します。 前に追加した並べ替えとフィルター処理の機能に加えて、GridView コントロールに各部門向けの入れ子になったコースの詳細が表示されるようになりました。
これで、並べ替え、フィルター処理、マスター詳細シナリオの概要が完了しました。 次のチュートリアルでは、コンカレンシーを処理する方法を説明します。