MVC5+EF6--3 排序、过滤和分页

近期学习MVC5+EF6,找到了Microsoft的原文,一个非常棒的系列,Getting Started with Entity Framework 6 Code First using MVC 5,网址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application。

这个系列的原文,可以上面网址找到。我也从网上找到了相关的译文。申明,这些译文,我不是原创,而是从网上找来的,为避免下次还要网上查询,现将这些译文整理放在上面。以后找时间将原文地址附上。

Contoso University示例网站演示如何使用Entity Framework 5创建ASP.NET MVC 4应用程序。

Entity Framework有三种处理数据的方式: Database First, Model First, and Code First. 本指南使用代码优先。其它方式请查询资料。

示例程序是为Contoso University建立一个网站。功能包括:学生管理、课程创建、教师分配。 本系列指南逐步讲述如何实现这一网站程序。

本示例程序基于 ASP.NET MVC.如果使用 ASP.NET Web Forms model, 请查看 Model Binding and Web Forms系列指南和 ASP.NET Data Access Content Map.

如有问题,可在这些讨论区提问: ASP.NET Entity Framework forum, the Entity Framework and LINQ to Entities forum, or StackOverflow.com.

如有问题,可在这些讨论区提问: ASP.NET Entity Framework forum, the Entity Framework and LINQ to Entities forum, or StackOverflow.com.

上一指南中你已经实现了一系列页面完成对Student 实体的 CRUD 操作.本指南将完成对数据的排序、过滤和分页。 还会创建一个实现了分组的简单页面.

下图显示做完之后的效果,点击列名可对数据进行排序.

为 Students Index页面添加排序

为了添加排序功能 需要改变Student 控制器的 Index方法 向其添加代码.

为 Index 方法添加排序功能

在 Controllers\StudentController.cs, 使用如下代码替换 Index 方法:

public ActionResult Index(string sortOrder)
{
   ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
   ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";
   var students = from s in db.Students
                  select 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 作为参数传递到行为方法。 参数值将为 "Name" 或"Date", 或后面跟着"_desc"。. 默认排序为升序 .

页面第一次加载时没有参数,因此switch 执行到最后默认 按 LastName的升序排列. 当用户点击了列标题之后, sortOrder 值将被传递到方法中.

ViewBag 变量记录了下次排序应该传递的排序参数:

ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";

这是交替语句. 第一句的意思是 sortOrder 参数为NULL或者空值,ViewBag.NameSortParm 应设为 "name_desc"; 否则,将其设为空值. 这两条语句使得当前排序和当前排序连接的关系如下:


当前排序


Last Name 链接


Date 链接


Last Name ascending


descending


ascending


Last Name descending


ascending


ascending


Date ascending


ascending


descending


Date descending


ascending


ascending

方法使用 LINQ to Entities 指明排序的列. 在switch 之前创建了一个 IQueryable 变量, 并在 switch 语句中修改此变量, 然后调用 ToList 方法. 在创建和修改 IQueryable 变量时, 不会向数据库发送查询命令. 直到将 IQueryable 对象通过如 ToList方法转成集合才会执行查询命令. 因此,代码只生成了一条查询语句且在 return View 语句才执行.

在Student Index 视图添加列标题排序链接

在Views\Student\Index.cshtml, 使用高亮部分的代码替换 <tr> 和<th> 元素:

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <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>
        <th></th>
    </tr>
 
    @foreach (var item in Model)
    {

代码使用 ViewBag 属性中的值设置链接中的排序参数.

运行并测试排序是否成功.

在Students Index 页面添加查询

添加一个文本框和一个按钮用于查询。

为 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.Students
                   select 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 参数,同时添加了where过滤条件.  where 语句只有在searchString 有值的时候执行.

注意:很多情况下在Entity Framework实体集或在内存集合中作为扩展方法调用同样的方法,通常结果是一样的,但有时结果会不同。比如,.NET Framework中如果给Contains方法传递一个空字符串作为参数将返回所有行,但Entity Framework provider for SQL Server Compact 4.0 返回零行。因此本例的代码(把Where语句放在If语句内)确保在SQL Server所有版本中得到同样的结果。而且.NET Framework 的Contains方法是大小写敏感的,但Entity Framework provider for SQL Server 默认大小写不敏感。因此,调用ToUpper 方法确保在你使用repository修改了代码之后得到的结果不会有变化,repository将返回一个IEnumerable集合而不是IQueryable对象。(当在IEnumerable 调用Contains方法,由 .NET Framework来处理;当在IQueryable 调用Contains时,是由 database provider来处理的。)

为 Student Index 视图添加搜索框

在 Views\Student\Index.cshtml, 在table标签之前添加如下高亮代码:

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

运行页面,测试过滤功能是否完成.

注意URL中并不包括查询字符串, 也就是说当你添加书签之后,再次使用此书签不会出现过滤.随后你将修改查询按钮使用关键词过滤信息.

为 Students Index 添加分页

为实现分页,请安装 PagedList.Mvc NuGet 包。在Index 方法做些改动,在Index 视图添加分页链接。 PagedList.Mvc 是很好用的分页排序包之一,这里使用只是为了示例并不是说 PagedList.Mvc就是最好的。

安装 PagedList.MVC NuGet 包

NuGet PagedList.Mvc 自动安装其依赖的 PagedList包.PagedList包安装 PagedList 集合类型和相应的针对IQueryable 或IEnumerable 的扩展方法 . 扩展方法根据IQueryable 或IEnumerable生成一个 PagedList 集合 ,  PagedList collection 提供分页相关的属性和方法。PagedList.Mvc安装一个 paging helper 用来显示分页按钮.

从工具菜单, 选择Library Package Manager -> Manage NuGet Packages.

在 Manage NuGet Packages 对话框, 选择 Online 然后在搜索框输入 "paged" .浏览到PagedList.Mvc 包, 点击安装.

在选择项目对话框选中项目, 点击 OK.

为 Index 方法添加分页功能

在 Controllers\StudentController.cs, 添加 using 语句引入 PagedList 命名空间:

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 (searchString != null)
   {
      page = 1;
   }
   else
   {
      searchString = currentFilter;
   }
 
   ViewBag.CurrentFilter = searchString;
 
   var students = from s in db.Students
                  select 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:  // Name ascending 
         students = students.OrderBy(s => s.LastName);
         break;
   }
 
   int pageSize = 3;
   int pageNumber = (page ?? 1);
   return View(students.ToPagedList(pageNumber, pageSize));
}

代码为方法添加 page 参数, 当前排序参数, 当前过滤参数:

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

页面第一次显示,或者用户没有点击分页链接或排序, 所有参数都是 null.  如果点击分页链接,  page 变量的值是要显示页的页码.

 ViewBag 属性记录当前排序, 为了保障分页数据一致,分页链接中需要包含排序信息:

ViewBag.CurrentSort = sortOrder;

另一个属性 ViewBag.CurrentFilter, 存储当前过滤参数. 页码链接必须包含此参数以保证分页数据对过滤有效, 当页面重新加载也能重置搜索框内的信息.如果过滤字符串在分页时发生变化, 页面跳转到第一页, 因为新的过滤导致数据不一样了. 当搜索框内容改变而且点击了提交按钮之后过滤才会改变. 在这种情况下,  searchString 参数的值不再是 null.

if (searchString != null)
        page = 1;
    else
        searchString = currentFilter;

方法最后, IQueryable的ToPagedList 扩展方法将 student 查询结果转为支持分页的集合中的一页. 这一页内容将传递给视图:

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

ToPagedList 方法需要一个页码参数.  (page ?? 1) 的意思是如果 page 不为null则返回, 如果 page是 null则返回1.

为 Student Index 视图添加分页链接

在Views\Student\Index.cshtml, 使用如下代码:

@model PagedList.IPagedList<ContosoUniversity.Models.Student>
@using PagedList.Mvc; 
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
 
@{
    ViewBag.Title = "Students";
}
 
<h2>Students</h2>
 
<p>
    @Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <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>
<br />
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
 
@Html.PagedListPager( Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter }) )

@model 语句表明使用 PagedList 对象而不再是List 对象.

using 语句引入 PagedList.Mvc 以便为分页按钮使用MVC helper .

此代码覆盖了之前的,BeginForm 标明使用 FormMethod.Get.

@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <p>
        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  
        <input type="submit" value="Search" />
    </p>

默认 BeginForm 提交使用 POST, 也就是说提交内容包含在 HTTP 消息中而不是 URL中. 如果指明 HTTP GET, 参数将通过UR传递, 添加书签之后 URL才有效.  W3C guidelines for the use of HTTP GET规范建议如果不会引起更新应使用 GET.

文本框的内容设置了默认值,这样当点击分页链接之后搜索关键词不会丢失.

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

排序链接中包含了过滤关键词以便保证重新排序时依然过滤:

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

当前页和总页数也有显示

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

如果没有内容, 将显示"Page 0 of 0". (这种情况 page number大于 page count,因为 Model.PageNumber 是1,Model.PageCount 是0.)

页码按钮通过 PagedListPager helper显示:

@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )

PagedListPager helper 提供很多自定义功能,详细信息请查看TroyGoode  / PagedList .

运行页面.

测试分页和过滤功能是否有效.

创建 About 页面显示 Student 统计信息

About将显示每个登记日期有多少学生进行登记 . 这需要使用分组. 通过以下步骤可实现:

  • 创建 一个视图模型类,包含要传递给视图的数据.
  • 修改Home 控制器的 About 方法.
  • 修改 About 视图.

创建View Model

新建 ViewModels 文件夹. 在此文件夹添加 EnrollmentDateGroup.cs 代码如下:

using System;
using System.ComponentModel.DataAnnotations;
 
namespace ContosoUniversity.ViewModels
{
    public class EnrollmentDateGroup
    {
        [DataType(DataType.Date)]
        public DateTime? EnrollmentDate { get; set; }
 
        public int StudentCount { get; set; }
    }
}

修改 Home Controller

在HomeController.cs, 添加如下 using 语句:

using ContosoUniversity.DAL;
using ContosoUniversity.ViewModels;

添加数据上下文变量:

    public class HomeController : Controller
    {
        private SchoolContext db = new SchoolContext();

About 方法的代码如下:

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

LINQ语句按登记日期对学生进行分组, 计算每个分组中的学生人数, 将结果存在 EnrollmentDateGroup视图模型变量中.

添加 Dispose 方法:

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

修改 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>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
        <td>
            @item.StudentCount
        </td>
    </tr>
}
</table>

运行程序查看结果.

可选内容: 将程序部署到 Windows Azure

时间: 2024-10-07 07:36:36

MVC5+EF6--3 排序、过滤和分页的相关文章

asp.net core 排序过滤分页组件:sieve(1)

使用asp.net core开发时避免不了要用一个合适的分页组件来让前端获取分页数据.github上面有一个开源的分页组件在这方面很适合我的使用,于是我把他的文档翻译一下,随后会分析它里面的源码.这是第一篇,介绍它如何使用. Sieve Sieves是一个.net core下面的简单.干净并且可扩展的框架,它对外暴露了排序,过滤和分页的功能. ASP.NET Core下的使用方式 在本例中,考虑一个带有Post实体的应用程序.在获取所有可用的帖子时,我们将使用Sieve添加排序.过滤和分页功能.

EF6与mvc5系列(3):在MVC应用程序中使用EF进行排序,过滤和分页

上节中,我们实现了基本增删查改功能,本节中要在Student的Index页面添加排序,分页和过滤功能,同时创建一个简单的分组页面. 在Student的Index页面添加列排序链接 为了在Index页面中实现排序.修改Index方法中的代码. 在Index方法中添加排序功能 修改Student控制器中的Index方法,在Index视图中添加代码. // GET: /Student/ public ActionResult Index(string sortOrder) { ViewBag.Name

MVC5 + EF6 + Bootstrap3 (11) 排序、搜索、分页

文章来源:Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc5-ef6-bs3-get-started-pagedlist.html 系列教程:MVC5 + EF6 + Bootstrap3 上一节:MVC5 + EF6 + Bootstrap3 (10) 数据查询页面 源码下载:点我下载 目录 前言 排序 搜索 分页 结尾 前言 上一节我们做到了如下的一个基础查询页面.本节我们向这个页面中加入排序.搜索和分页功能. 排序 从上图中的地址栏中可以看到

Contoso 大学 - 3 - 排序、过滤及分页

原文地址: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 页面加入排序.过滤以及分页的功能.还要创建一个页面完成

MVC4中的列表排序、过滤、分页

在上一个课程中,我们已经学习了如何使用 EF 对 Student 实体进行增.删.改.查处理.这次的课程我们将对学生的 Index 页面加入排序.过滤以及分页的功能.还要创建一个页面完成简单的分组. 下面的截图展示了完成之后的页面,列的标题作为链接支持用户通过点击完成排序,点击标题可以在升序和降序之间进行切换. 3-1  在 Students 的 Index 页面增加列标题链接 为 Index 页面增加排序的功能,我们需要修改 Student 控制器的 Index 方法,还需要为 Student

DRF框架(八)——drf-jwt手动签发与校验、过滤组件、筛选组件、排序组件、分页组件

自定义drf-jwt手动签发和校验 签发token源码入口 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口,不然进不了登录页面 获取提交的username和password 1)rest_framework_jwt.views.ObtainJSONWebToken 的 父类 JSONWebTokenAPIView 的 post 方法 接受有username.password的post请求校验数据,并且签发token 2)post方法将请求数据交给 r

签发token、校验token、多方式登录签发token的实现、自定义认证反爬规则的认证类、admin使用自定义User表:新增用户密码密文、群查接口各种筛选组件数据准备、drf搜索过滤组件、drf排序过滤组件、drf基础分页组件

签发token 源码入口 # 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口 # 1)rest_framework_jwt.views.ObtainJSONWebToken 的 父类 JSONWebTokenAPIView 的 post 方法 # 接收有username.password的post请求 # 2)post方法将请求得到的数据交给 rest_framework_jwt.serializer.JSONWebTokenSerializer 处

MVC5+EF6 入门完整教程九

前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Controller中获取表单数据 文章三 EF的整个开发过程 文章四 EF基本的CRUD和常用的HtmlHelper 文章五 使用布局页(模板页)改造UI 文章六 分部视图(Partial View) 文章七 排序过滤分页 文章八 不丢失数据进行数据库结构升级 以上如果有不清楚的可以再回去看一下. 文

MVC5+EF6 入门完整教程

MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用 MVC5+EF6 入门完整教程10:多对多关联表更新&使用原生SQL@20150521 MVC5+EF6 入门完整教程9:多表数据加载@20150212 MVC5+EF6 入门完整教程8 :不丢失数据进行数据库结构升级 @20141215 MVC5+EF6 入门完整教程7 :排序过滤分页 @20141201 MVC5+EF6 入门完整教程6 :分部视图(Partial View) @20141117 MVC5+EF6 入门完整教程