使用 Entity Framework 4.0 和 ObjectDataSource 控件,第 3 部分:排序和筛选
作者 :Tom Dykstra
本教程系列基于由入门使用 Entity Framework 4.0 教程系列创建的 Contoso University Web 应用程序。 如果未完成前面的教程,作为本教程的起点,可以下载已创建 的应用程序 。 还可以下载完整教程系列创建 的应用程序 。 如果对教程有疑问,可将其发布到 ASP.NET 实体框架论坛。
在上一教程中,你在使用实体框架和 ObjectDataSource
控件的 n 层 Web 应用程序中实现了存储库模式。 本教程演示如何进行排序和筛选以及处理主-详细信息方案。 你将向 Departments.aspx 页面添加以下增强功能:
- 允许用户按名称选择部门的文本框。
- 网格中显示的每个部门的课程列表。
- 通过单击列标题进行排序的功能。
添加对 GridView 列进行排序的功能
打开 Departments.aspx 页,并将属性SortParameterName="sortExpression"
添加到名为 的ObjectDataSource
DepartmentsObjectDataSource
控件。 (稍后将创建一个 GetDepartments
方法,该方法采用名为 sortExpression
.) 控件的开始标记的标记现在类似于以下示例。
<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" >
将 AllowSorting="true"
属性添加到 控件的 GridView
开始标记。 控件的开始标记的标记现在类似于以下示例。
<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);
}
此代码将 sort 参数传递给存储库方法。
运行 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" />
在名为 的ObjectDataSource
DepartmentsObjectDataSource
控件中,执行以下操作:
- 为名为
nameSearchString
的参数添加一个SelectParameters
元素,用于获取在 控件中SearchTextBox
输入的值。 - 将
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
选择包含搜索字符串的项。 如果搜索字符串为空,则将选择所有记录。 请注意,在一个语句中一起指定方法调用时,如 (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
控件,并将其数据绑定到实体导航属性中的数据Courses
Department
。
打开 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 文件,通过在 方法中创建的对象查询中调用 Include
方法来指定导航属性的GetDepartmentsByName
预先加载Courses
。 方法 return
中的 GetDepartmentsByName
语句现在类似于以下示例。
return context.Departments.Include("Person").Include("Courses").
OrderBy("it." + sortExpression).Where(d => d.Name.Contains(nameSearchString)).ToList();
运行页面。 除了前面添加的排序和筛选功能外,GridView 控件现在还显示每个部门的嵌套课程详细信息。
这将完成排序、筛选和大纲-详细信息方案的介绍。 在下一教程中,你将了解如何处理并发。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈