原文地址:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application

在上一个课程中,我们已经学习了如何使用 EF 对 Student 实体进行增、删、改、查处理。这次的课程我们将对学生的 Index 页面加入排序、过滤以及分页的功能。还要创建一个页面完成简单的分组。

下面的截图展示了完成之后的页面,列的标题作为链接支持用户通过点击完成排序,点击标题可以在升序和降序之间进行切换。

3-1  在 Students 的 Index 页面增加列标题链接

为 Index 页面增加排序的功能,我们需要修改 Student 控制器的 Index 方法,还需要为 Student 视图增加代码。

3-1-1  为 Index 方法增加排序功能

打开 Controllers\StudentController.cs,将 Index 方法替换为如下的代码。

public ViewResult Index(string sortOrder){    ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";    ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";var students = from s in db.Studentsselect s;switch (sortOrder)    {case "Name desc":            students = students.OrderByDescending(s => s.LastName);break;case "Date":            students = students.OrderBy(s => s.EnrollmentDate);break;case "Date desc":            students = students.OrderByDescending(s => s.EnrollmentDate);break;default:            students = students.OrderBy(s => s.LastName);break;    }return View(students.ToList());}

这段代码从 URL 中接收名为 sortOrder 的参数,这个参数由 ASP.NET MVC 作为参数传递给 Action 方法。这个参数可以是  “Name” 或者 “Date”, 可能还有一个空格隔开的 desc 来指定降序。

当第一次请求 Index 的时候,没有参数,学生使用 LastName 的升序顺序显示。这是通过 switchdefault 代码段指定的,当用户点击一个列的标题链接的时候,合适的 sortOrder 值需要通过查询字符串传递进来。

两个 ViewBag 变量用来为视图提供合适的查询字符串链接值。

ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";

这里使用了条件语句,第一个用来指定当 sortOrder 参数为 null 或者空串的时候, ViewBag.NameSortParm 应用被设置为 Name desc,其他情况下,应该被设置为空串。

这里有四种可能,依赖于当前的排序情况:

  • 如果当前的排序规则为 LastName 升序,那么,LastName 链接应该设置为降序,Enrollment Date 链接必须被设置为按日期升序。
  • 如果当前的排序规则为 LastName 降序,那么,LastName 链接应该设置为升序,排序串应该为空串,日期为升序。
  • 如果当前排序的规则为 Date 升序,那么,链接应该为 LastName 升序和日期升序。
  • 如果当前的排序规则为 Date 降序,那么,链接应该为 LastName 升序和日期降序。

方法中使用 LINQ to Entities 来指定排序,在 switch 之前,代码首先创建一个 IQueryable 变量,在 switch 语句中修改这个查询表达式,最后调用 ToList 方法。在创建和修改查询表达式 IQueryable 的时候,并没有将查询发送到数据库中执行,查询直到将 IQueryable 对象驼工调用类似 ToList 方法转换到集合对象的时候才会执行,因此,代码中查询直到最后的 return View 才会被执行。

3-2-2  为 Index 视图增加列标题链接

Views\Student\Index.cshtml,使用如下的代码替换标题行中的 <tr> 和 <th> 元素。

<tr>    <th></th>    <th>        @Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm })    </th>    <th>        First Name    </th>    <th>        @Html.ActionLink("Enrollment Date", "Index", new { sortOrder=ViewBag.DateSortParm })    </th></tr>

这段代码使用 ViewBag 属性来设置超级链接中包含适当的查询字符串。

运行页面,点击列标题,来验证排序是否正常。

3-2  为 Index 页面增加搜索框

为 Index 页面增加过滤功能,需要增加一个文本框和一个提交按钮,然后,对 Index 方法进行一些修改,文本框允许你输入一个搜索字符串,用来在 FirstName 和 LastName 中进行搜索。

3-2-1  为 Index 方法增加过滤功能

打开 Controllers\StudentController.cs 文件,使用下面的代码替换 Index 方法。

public ViewResult Index(string sortOrder, string searchString){    ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";    ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";var students = from s in db.Studentsselect s;if (!String.IsNullOrEmpty(searchString))    {        students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())                               || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));    }switch (sortOrder)    {case "Name desc":            students = students.OrderByDescending(s => s.LastName);break;case "Date":            students = students.OrderBy(s => s.EnrollmentDate);break;case "Date desc":            students = students.OrderByDescending(s => s.EnrollmentDate);break;default:            students = students.OrderBy(s => s.LastName);break;    }

return View(students.ToList());}

现在,为 Index 方法增加了一个参数 searchString ,LINQ 语句中也增加了一个 where 子句,用来选择在 FirstName 或者 LastName 中包含过滤字符串的学生。搜索串来自文本框的输入,后面需要你在视图中加入它。增加的 where 条件子句仅仅在提供了搜索串的情况下才会被处理。

if (!String.IsNullOrEmpty(searchString)){    students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())                           || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));}

注意:在传递一个空串的时候,.NET 实现的 Contains 方法将会返回所有的数据行,但是 EF Provider for SQL Server Compact 4.0 对于空串不返回任何行。因此,代码中增加了一个 if 判断语句,以确保对于所有的 SQL Server 都有一致的处理结果。另外,.NET 实现的 Contains 默认进行区分大小写的字符串比较,因此,通过调用 ToUpper 方法显式转换字符串为大写,

以确保在转换到使用资源库模式的时候不需要修改代码。那个时候将会返回一个 IEnumerable 集合而不是 IQueryable 对象 ( 在调用 IEnumerable 集合上的 Contains 方法的时候,使用 .NET 实现的方法,在调用 IQueryable 对象上的 Contains 方法的时候,使用数据库 Provider 提供的实现 )。

3-2-2  在 Student 视图上加入搜索框

在视图 Views\Student\Index.cshtml 上,table 开始标记之前,增加一个标题,一个文本框,以及一个 Search 按钮。

@using (Html.BeginForm()){    <p>        Find by name: @Html.TextBox("SearchString")          <input type="submit" value="Search" /></p>}

运行程序,输入一个搜索串,然后点击 Search 按钮来查看过滤的效果。

3-3  在 Student 的 Index 视图上增加分页

为了支持分页,你需要通过 NuGet 包管理器安装 PagedList ,然后,需要在 Index 方法中增加一些代码,在视图中增加分页的链接,下面的截图展示了分页的链接。

3-3-1  安装 PagedList 包

NuGet 中的 PagedList 包将会增加一种类型:PagedList,当将查询结果传入到 PagedList 中后,它提供的一系列属性和方法使得排序更加简单。

在 Visual Studio 中,确信选中了当前的项目,而不是解决方案。在 Tools 菜单中,选择 Library Package Manager,然后选择 Add Library Package Reference。

在 Add Library Package Reference 对话框中,点击左边的 Online 窗格,然后在搜索框中输入 pagedlist ,在看到 PagedList 包之后,点击 Install。

3-3-2  为 Index 方法增加分页功能

打开 Controllers\StudentController.cs,在代码的前面为 PagedList 命名空间增加 using 语句.

using PagedList;

将 Index 方法替换成如下的代码。

 public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)        {            ViewBag.CurrentSort = sortOrder;            ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";            ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";

if (Request.HttpMethod == "GET")            {                searchString = currentFilter;            }else            {                page = 1;            }            ViewBag.CurrentFilter = searchString;

var students = from s in db.Studentsselect s;if (!String.IsNullOrEmpty(searchString))            {                students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())                                       || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));            }switch (sortOrder)            {case "Name desc":                    students = students.OrderByDescending(s => s.LastName);break;case "Date":                    students = students.OrderBy(s => s.EnrollmentDate);break;case "Date desc":                    students = students.OrderByDescending(s => s.EnrollmentDate);break;default:                    students = students.OrderBy(s => s.LastName);break;            }

int pageSize = 3;int pageNumber = (page ?? 1);return View(students.ToPagedList(pageNumber, pageSize));        }

方法又增加了一个 page 参数,方法的签名如下所示。

public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)

当第一次显式这个页面的时候,或者用户没有点击分页链接的时候,page 参数将会是 null。如果分页链接被点击了,page 参数将会包含需要显示的页码。

ViewBag 中的 CurrentSort 属性用来提供当前的排序顺序,它必须被包含到当前的分页链接中,以便在分页处理过程中保持当前的排序规则。

ViewBag.CurrentSort = sortOrder;

其它的 ViewBag 属性为视图提供当前的过滤串,因为这个过滤串在页面被重新显示的时候,必须重新回到文本框中,另外,这个串也必须包含在分页链接中,以便在分页过程中,保持过滤效果。最后,如果在分页的过程中修改了过滤串,那么页码将会回到第一页,因为新的过滤规则返回了不同的数据,很可能原来的页码在这时候已经不再存在了。

if (Request.HttpMethod == "GET"){    searchString = currentFilter;}else{    page = 1;}ViewBag.CurrentFilter = searchString;

在方法的最后,查询学生的表达式被转换为 PagedList ,而不再是通常的 List,这样传递到视图中的就是支持分页的集合,代码如下:

int pageSize = 3;int pageNumber = (page ?? 1);return View(students.ToPagedList(pageNumber, pageSize));

ToPagedList 方法需要一个页码值,两个问号用来为可空的页码提供一个默认值,表达式 ( page ?? 1 ) 意味着如果 page 有值得话返回这个值,如果是 null 的话,返回 1。

3-3-3  为视图增加分页链接

Views\Student\Index.cshtml中,使用下面的代码替换原有代码。

@model PagedList.IPagedList<ContosoUniversity.Models.Student>

@{    ViewBag.Title = "Students";}

<h2>Students</h2>

<p>    @Html.ActionLink("Create New", "Create")</p>@using (Html.BeginForm()){    <p>        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)          <input type="submit" value="Search" /></p>}<table><tr>    <th></th>    <th>        @Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })    </th>    <th>        First Name    </th>    <th>        @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })    </th></tr>

@foreach (var item in Model) {    <tr>        <td>            @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |            @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |            @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })        </td>        <td>            @Html.DisplayFor(modelItem => item.LastName)        </td>        <td>            @Html.DisplayFor(modelItem => item.FirstMidName)        </td>        <td>            @Html.DisplayFor(modelItem => item.EnrollmentDate)        </td>    </tr>}

</table>

<div>    Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)    of @Model.PageCount

    @if (Model.HasPreviousPage)    {        @Html.ActionLink("<<", "Index", new { page = 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter  })        @Html.Raw(" ");        @Html.ActionLink("< Prev", "Index", new { page = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter  })    }else    {        @:<<        @Html.Raw(" ");        @:< Prev    }

    @if (Model.HasNextPage)    {        @Html.ActionLink("Next >", "Index", new { page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter  })        @Html.Raw(" ");        @Html.ActionLink(">>", "Index", new { page = Model.PageCount, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter  })    }else    {        @:Next >        @Html.Raw(" ")        @:>>    }</div>

视图最前面的 @model 语句指定现在传递到视图的不再是 List 而是 PagedList 。

文本框使用当前的搜索串进行初始化,以便在分页的时候不会丢失搜索串。

 Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  

列的标题链接使用查询串来传递当前的搜索串,以便传递给控制器当前的搜索和排序。

@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })

在当前页面的最后,通过一行来显示分页的导航 UI。

Page [current page number] of [total number of pages] << < Prev Next > >>

<< 符号连接到第一页, < Prev 链接到上一页,等等。如果用户当前就在第一页,那么,链接到第一页的链接就会被禁用,类似地,如果用户当前在最后一页,导航到最后一页就会被禁用,每一个分页链接传递页码以及当前的排序串和搜索串到控制器,这使得可以在分页的同时维护排序和过滤规则。

如果没有页可以显示,将会显示 “Page 0 of 0 “,在这种情况下,页面数字就会大于页数,因为 Model.PageNumber 是 1,但是 Model.PageCount 为 0。

运行页面。

在不同的排序规则下,点击分页链接,确认分页在正常工作。然后输入一个过滤串,再次点击分页的链接,确认在排序和过滤的同时,分页可以正常工作。

3-4  创建 About 页面显示学生的统计情况

在 Contoso 大学网站的 About 页面,我们希望能够显示每个注册日有多少学生注册。这需要进行分组,然后在每个组上进行简单地计算,需要完成下列工作:

  • 创建用于传递数据到视图的 ViewModel
  • 修改 Home 控制器中的 About 方法
  • 修改 About 视图

3-4-1  创建 ViewModel

创建 ViewModels 文件夹,在文件夹中,创建 EnrollmentDateGroup.cs 类文件,将代码替换为如下代码:

using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.ViewModels{public class EnrollmentDateGroup    {        [DisplayFormat(DataFormatString = "{0:d}")]public DateTime? EnrollmentDate { get; set; }

public int StudentCount { get; set; }    }}

3-4-2  修改 Home 控制器

增加如下的 using 语句。

using ContosoUniversity.DAL;using ContosoUniversity.Models;using ContosoUniversity.ViewModels;

增加一个数据库上下文变量。

private SchoolContext db = new SchoolContext();

使用如下的代码替换 About 方法。

public ActionResult About(){var data = from student in db.Students               group student by student.EnrollmentDate into dateGroupselect new EnrollmentDateGroup()               {                   EnrollmentDate = dateGroup.Key,                   StudentCount = dateGroup.Count()               };return View(data);}

LINQ 语句通过注册日期对学生进行分组,计算每一组中的实体数量,最后将查询结果保存为 EnrollmentDateGroup 对象。

3-4-3  增加 Dispose 方法

protected override void Dispose(bool disposing){    db.Dispose();base.Dispose(disposing);}

3-4-4  修改 About 视图

打开 Views\Home\About.cshtml ,替换为如下代码。

@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup>

@{    ViewBag.Title = "Student Body Statistics";}

<h2>Student Body Statistics</h2>

<table>    <tr>        <th>            Enrollment Date        </th>        <th>            Students        </th>    </tr>

@foreach (var item in Model) {    <tr>        <td>            @String.Format("{0:d}", item.EnrollmentDate)        </td>        <td>            @item.StudentCount        </td>    </tr>}</table>

运行页面,每个注册日注册学生的数量显示在表格中。

现在,你已经看到了如何创建数据模型,以及实现基本的增、删、改、查处理,排序、过滤、分页和分组功能。下一次,我们将会扩展数据模型开始更加高级的内容。

转载于:https://www.cnblogs.com/itjeff/p/4140704.html

Contoso 大学 - 3 - 排序、过滤及分页相关推荐

  1. jpa 分页 排序 过滤_使用JPA标准@ViewScoped通过分页,过滤和排序进行Primefaces DataTable延迟加载...

    jpa 分页 排序 过滤 Primefaces数据表惰性分页有效,但是在Web上使用Criteria搜索完整示例后,我感到非常沮丧. 所以我混合了来自 http://stackoverflow.com ...

  2. SQL条件查询,分组查询,排序查询,分页查询

    DQL查询操作(条件查询,分组查询,排序查询,分页查询) 文章目录 DQL查询操作(条件查询,分组查询,排序查询,分页查询) 一.查询语法 二.基础查询 三.条件查询 四.排序查询 五.分组查询 六. ...

  3. php 点击表头排序,TP5+ajax实现点击表格表头切换排序,带分页

    TP5+ajax实现点击表格表头切换排序,带分页 2018-08-15 14:59:06ThinkPHP php接收页码请求的地址 /** * ajax 无刷新分页 * param $page int ...

  4. 演练5-3:Contoso大学校园管理系统3

    在前面的教程中,我们使用了一个简单的数据模型,包括三个数据实体.在这个教程汇中,我们将添加更多的实体和关系,按照特定的格式和验证规则等自定义数据模型. Contoso大学校园管理系统的数据模型如下. ...

  5. ASP.NET Core Web API基于RESTFul APIs的集合结果过滤和分页

    译者荐语:如何在RESTFul APIs中进行集合结果分页?还是用客户端来拼接链接地址么? 原文来自互联网,由长沙DotNET技术社区[邹溪源]翻译.如译文侵犯您的版权,请联系小编,小编将在24小时内 ...

  6. 使用nhmicro使分库分表支持排序后的分页查询

    2019独角兽企业重金招聘Python工程师标准>>> 常见的在创建数据时根据规则分库分表保存,查询时往往只支持按照id进行查询. Nhmicro(开源地址为 https://git ...

  7. APIView(认证,权限,限流,过滤,分页,序列化,排序)

    概述: 一.身份认证: 1: 配置身份认证后端:注意:只作用于DRF视图,对django视图不起作用. 主要有两个认证后端,一个是基本认证后端,一个是seesion认证后端.BasicAuthenti ...

  8. asp.net core 排序过滤分页组件:sieve(2)表达式树的复习

    在Sieve组件中使用了很多关于表达式树的知识,但在我们日常的工作中写表达式树的机会是非常少的,至少在我的编程生涯中没怎么写过表达式树(可能也就是3,4次).所以,为了能够看懂Sieve里面的源代码, ...

  9. 用ASP.NET Core 2.1 建立规范的 REST API -- 翻页/排序/过滤等

    本文所需的一些预备知识可以看这里:  用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 和  用ASP.NET Core 2.0 建立规范的 REST API -- 预 ...

最新文章

  1. linux下基本命令
  2. 全国计算机等级考试培训方案,第23次全国计算机等级考试培训安排.doc
  3. 初探性能优化——2个月到4小时的性能提升
  4. InnoDB的ib_logfile写入策略
  5. 北邮高级语言设计基于java期末_北邮《高级语言程序设计》第三次阶段作业带答案...
  6. 「造个轮子」——cicada(轻量级 WEB 框架)
  7. 其他脚本与 asp.net 脚本一起验证时容易出的问题
  8. WebSocket简单使用
  9. 通信原理 —— 绪论
  10. ELK + kafka 分布式日志解决方案
  11. ueditor 编辑器增加css样式_ueditor编辑器实现语法高亮
  12. Android Java编写布局
  13. linux 查看分区
  14. 学生管理系统(源码)(C语言版)
  15. 《第一行代码》第三版之我的第一行Android代码(一)
  16. 初次汇编程序 masm5
  17. ArcGIS教程 - 9 矢量数据空间分析
  18. 开发者头条(一):导航页
  19. 中国物流市场趋势报告、技术动态创新及市场预测
  20. 【互联网营销基础知识】新媒体工具亲民替代款有什么?

热门文章

  1. 【python】匿名函数与装饰器
  2. 域间套接字socketpair
  3. 一个好的web前端开发者,是怎么学习的?
  4. 学会这6个强大的CSS选择器,将真正帮你写出干净的CSS代码!
  5. C - 数据结构实验之栈与队列三:后缀式求值
  6. 微信小程序怎么扩展服务器,小程序服务器可扩展的配置方案
  7. 轴固定位置_全面总结:轴零件固定方式及特点
  8. 支付宝开放平台开发助手_支付宝:如何创建和接入支付宝电脑网站支付-新手必备...
  9. 清空div中的内容而不刷新整个页面_Vue中的$nextTick机制
  10. 关于STM32系列单片机中断触发时间问题