使用 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 页。

Internet Explorer 窗口的屏幕截图,其中显示了包含学生表的“学生列表”视图。

Internet Explorer 窗口的屏幕截图,其中显示了“按部门显示的课程”和“按名称显示的课程”视图。

Internet Explorer 窗口的屏幕截图,其中显示了“学生正文统计信息”视图,其中包含注册日期表。

Internet Explorer 窗口的屏幕截图,其中显示了“按姓名查找学生”视图,其中在搜索查询中输入了字母 g。

使用 EntityDataSource“Where”属性筛选数据

打开在上一教程中创建的 Students.aspx 页。 按照当前配置,页面中的 GridView 控件显示实体集中的所有名称 People 。 但是,你希望仅显示学生,可以通过选择 Person 具有非 Null 注册日期的实体来查找这些学生。

切换到 “设计” 视图并选择控件 EntityDataSource 。 在“属性” 窗口中,将 Where 属性设置为 it.EnrollmentDate is not null

Image01

在 控件的 EntityDataSource 属性中使用的Where语法是 Entity SQL。 实体 SQL 类似于 Transact-SQL,但它是自定义的,用于实体而不是数据库对象。 在表达式 it.EnrollmentDate is not null中, 单词 it 表示对查询返回的实体的引用。 因此, it.EnrollmentDate 引用 EnrollmentDate 控件返回的 Person 实体的 EntityDataSource 属性。

运行页面。 学生列表现在仅包含学生。 (未显示注册日期的行。)

Internet Explorer 窗口的屏幕截图,其中显示了包含学生表的“学生列表”视图。

使用 EntityDataSource“OrderBy”属性来订购数据

你还希望此列表在首次显示时按名称顺序显示。 当 Students.aspx 页面仍在 设计 视图中打开且 EntityDataSource 控件仍处于选中状态时,在 “属性” 窗口中将 OrderBy 属性设置为 it.LastName

Image05

运行页面。 学生列表现在按姓氏排序。

Image04

使用控件参数设置“Where”属性

与其他数据源控件一样,可以将参数值传递给 Where 属性。 在本教程的第 2 部分创建的 Courses.aspx 页上,可以使用此方法显示与用户从下拉列表中选择的部门关联的课程。

打开 Courses.aspx 并切换到 “设计” 视图。 将第二 EntityDataSource 个控件添加到页面,并将其命名为 CoursesEntityDataSource。 将其连接到 SchoolEntities 模型,并选择 Courses 作为 EntitySetName 值。

“属性” 窗口中,单击“ Where 属性”框中的省略号。 (在使用“属性”窗口之前,请确保CoursesEntityDataSource控件仍处于选中状态。)

Image06

将显示“ 表达式编辑器 ”对话框。 在此对话框中,选择“ 基于提供的参数自动生成 Where 表达式”,然后单击“ 添加参数”。 将参数 DepartmentID命名为 ,选择 Control 作为 参数源 值,然后选择 DepartmentsDropDownList 作为 ControlID 值。

Image07

单击“显示高级属性”,然后在“表达式编辑器”对话框的“属性”窗口中,将 Type 属性更改为 Int32

Image15

完成后,单击“确定”。

在下拉列表下方,将控件 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

现在,你已完成使用设计器,请切换到“源视图”,并将 控件ContextTypeName="ContosoUniversity.DAL.SchoolEntities"CoursesEntityDataSourceDefaultContainer 名称属性替换为 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 仅显示所选部门提供的课程。

Image09

使用 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

“源” 视图中,将 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>

、 和 属性的Select语法类似于 Transact-SQL,但指定当前实体的 关键字 (keyword) 除外itWhereGroupBy

添加以下标记以创建控件 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>

运行页面以查看按注册日期显示学生人数的列表。

Internet Explorer 窗口的屏幕截图,其中显示了带有注册日期表的“学生正文统计信息”视图。

使用 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>

请注意,控件 EntityDataSourceInclude 属性设置为 Department。 在数据库中, Course 表不包含部门名称;它包含外 DepartmentID 键列。 如果直接查询数据库,若要获取系名称以及课程数据,则必须联接 CourseDepartment 表。 通过将 属性设置为 IncludeDepartment,可以指定实体框架应在获取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因此导航属性包含实体DepartmentDepartment (如果这是一对多关系,则属性将包含 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

运行页面。 初始显示按部门和课程标题按顺序显示所有课程的列表。

Internet Explorer 窗口的屏幕截图,其中显示了“按部门显示的课程”和“按名称显示的课程” 视图。

输入“m”并单击“ 搜索 ”以查看标题以“m”开头的所有课程, (搜索不区分大小写) 。

Image12

使用“Like”运算符筛选数据

通过使用控件的 属性中的EntityDataSourceWhere运算符,可以实现类似于QueryExtender控件的 StartsWithContainsEndsWith 搜索类型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 默认值为“%”。

Image13

在文本框中输入字母“g”,然后单击“ 搜索”。 你将看到名字或姓氏中带有“g”的学生列表。

Internet Explorer 窗口的屏幕截图,其中显示了“按姓名查找学生”视图,其中在搜索查询中输入了字母 g。

现在,你已显示、更新、筛选、排序和分组来自各个表的数据。 在下一教程中,你将开始处理相关数据 (主详细信息方案) 。