作者 :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
。 但是,你希望仅显示学生,可以通过选择 Person
具有非 Null 注册日期的实体来查找这些学生。
切换到 “设计” 视图并选择控件 EntityDataSource
。 在“属性” 窗口中,将 Where
属性设置为 it.EnrollmentDate is not null
。
在 控件的 EntityDataSource
属性中使用的Where
语法是 Entity SQL。 实体 SQL 类似于 Transact-SQL,但它是自定义的,用于实体而不是数据库对象。 在表达式 it.EnrollmentDate is not null
中, 单词 it
表示对查询返回的实体的引用。 因此, it.EnrollmentDate
引用 EnrollmentDate
控件返回的 Person
实体的 EntityDataSource
属性。
运行页面。 学生列表现在仅包含学生。 (未显示注册日期的行。)
使用 EntityDataSource“OrderBy”属性来订购数据
你还希望此列表在首次显示时按名称顺序显示。 当 Students.aspx 页面仍在 设计 视图中打开且 EntityDataSource
控件仍处于选中状态时,在 “属性” 窗口中将 OrderBy 属性设置为 it.LastName
。
运行页面。 学生列表现在按姓氏排序。
使用控件参数设置“Where”属性
与其他数据源控件一样,可以将参数值传递给 Where
属性。 在本教程的第 2 部分创建的 Courses.aspx 页上,可以使用此方法显示与用户从下拉列表中选择的部门关联的课程。
打开 Courses.aspx 并切换到 “设计” 视图。 将第二 EntityDataSource
个控件添加到页面,并将其命名为 CoursesEntityDataSource
。 将其连接到 SchoolEntities
模型,并选择 Courses
作为 EntitySetName 值。
在 “属性” 窗口中,单击“ Where 属性”框中的省略号。 (在使用“属性”窗口之前,请确保CoursesEntityDataSource
控件仍处于选中状态。)
将显示“ 表达式编辑器 ”对话框。 在此对话框中,选择“ 基于提供的参数自动生成 Where 表达式”,然后单击“ 添加参数”。 将参数 DepartmentID
命名为 ,选择 Control 作为 参数源 值,然后选择 DepartmentsDropDownList 作为 ControlID 值。
单击“显示高级属性”,然后在“表达式编辑器”对话框的“属性”窗口中,将 Type
属性更改为 Int32
。
完成后,单击“确定”。
在下拉列表下方,将控件 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
。
现在,你已完成使用设计器,请切换到“源视图”,并将 控件ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
的 CoursesEntityDataSource
和 DefaultContainer
名称属性替换为 ConnectionString
属性。 完成后,控件的标记将如以下示例所示。
<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
“学生正文统计信息”:
<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
语法类似于 Transact-SQL,但指定当前实体的 关键字 (keyword) 除外it
。Where
GroupBy
添加以下标记以创建控件 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) 。 它通常也独立于实体框架,但用于导航属性的语法对实体框架是唯一的。
在本教程的此部分中,你将使用 QueryExtender
控件来筛选和排序数据,其中一个 order-by 字段将是导航属性。
(如果希望使用代码而不是标记来扩展控件自动生成EntityDataSource
的查询,可以通过处理 QueryCreated
事件来执行此操作。这也是控件扩展EntityDataSource
控件查询的方式QueryExtender
。)
打开 Courses.aspx 页,在前面添加的标记下方,插入以下标记以创建标题、用于输入搜索字符串的文本框、搜索按钮和 EntityDataSource
绑定到 Courses
实体集的控件。
<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
实体时执行获取相关Department
实体的工作。 然后,实体 Department
存储在实体 Department
的导航属性中 Course
。 (默认情况下,SchoolEntities
数据模型设计器生成的类在需要时检索相关数据,并且已将数据源控件绑定到该类,因此不需要设置 Include
属性。但是,设置它可以提高页面的性能,因为否则实体框架会单独调用数据库来检索实体和相关Department
实体的数据Course
。)
在 EntityDataSource
刚刚创建的控件之后,插入以下标记以创建 QueryExtender
绑定到该 EntityDataSource
控件的控件。
<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
因此导航属性包含实体Department
。Department
(如果这是一对多关系,则属性将包含 collection。) 若要获取部门名称,必须指定 Name
实体的属性 Department
。
最后,添加控件 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>
第一列是显示部门名称的模板字段。 数据绑定表达式指定 Department.Name
,正如你在 控件中看到的那样 QueryExtender
。
运行页面。 初始显示按部门和课程标题按顺序显示所有课程的列表。
输入“m”并单击“ 搜索 ”以查看标题以“m”开头的所有课程, (搜索不区分大小写) 。
使用“Like”运算符筛选数据
通过使用控件的 属性中的EntityDataSource
Where
运算符,可以实现类似于QueryExtender
控件的 StartsWith
、 Contains
和 EndsWith
搜索类型Like
的效果。 本教程的此部分介绍如何使用 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
二部分定义子字符串搜索 (LIKE %FirstMidName% or LIKE %LastName%
) ,该子字符串搜索在文本框中输入的任何内容,
运行页面。 最初,你会看到所有学生,因为参数的 StudentName
默认值为“%”。
在文本框中输入字母“g”,然后单击“ 搜索”。 你将看到名字或姓氏中带有“g”的学生列表。
现在,你已显示、更新、筛选、排序和分组来自各个表的数据。 在下一教程中,你将开始处理相关数据 (主详细信息方案) 。