MVC5 Entity Framework学习参加排序、筛选和排序功能

时间:2024-01-15 09:46:14

上一篇文章实现Student 基本的实体CRUD操作。本文将展示如何Students Index页添加排序、筛选和分页功能。

以下是排序完成时、经过筛选和分页功能截图,您可以在列标题点击排序。

MVC5 Entity Framework学习参加排序、筛选和排序功能

1.为 Students Index页面加入列排序链接

要为Students Index页面加入排序功能,你须要改动Student controller的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參数。该參数是"Name"或"Date"。使用三元运算符推断并加下划线和"desc"来指名这是一个降序排序,默认是按升序排序。

第一次訪问Index页面时是没有查询字符串的,students依照LastName作升序排序显示。这是由switch语句中的default指定的。当用户点击某列的标题链接时,URL的查询字符串中就含有了对应的sortOrder值。

这里使用了两个ViewBag变量以便视图能够将合适的查询字符串提供给列标题链接。

ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ?

"name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";

这里使用了三元运算符,上面第一个指明假如sortOrder參数为null或为空。则ViewBag.NameSortParm被赋值为"name_desc"。否则将其赋值为空。其排序规则为:

Current sort order Last Name Hyperlink Date Hyperlink
Last Name ascending descending ascending
Last Name descending ascending ascending
Date ascending ascending descending
Date descending ascending ascending

该方法使用LINQ to Entities来指明要排序的列,上面的代码在switch语句前新建了一个 IQueryable变量,然后在switch中改动它,最后在switch语句后调用ToList方法。当你创建并改动IQueryable变量时,并没有向数据库发送查询命令,直到调用ToList方法将IQueryable 对象转换为一个集合时才真正的运行查询命令。因此,直到return View语句,才会运行查询语句。

作为还有一种为每个排序编写不同的LINQ语句的替代方法。能够使用动态创建LINQ句。

为Student Index视图加入列标题链接

打开Views\Student\Index.cshtml,加入以下的代码

<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属性使用对应的查询字符串来设置列标题链接的值。

执行项目,点击Last Name和Enrollment Date行标题,验证排序功能

MVC5 Entity Framework学习参加排序、筛选和排序功能



点击Last Name标题。students 将按降序排列

MVC5 Entity Framework学习参加排序、筛选和排序功能

2.向Students Index页面加入搜索框

要在Students Index页面中加入搜索功能,你须要在视图中加入一个文本框和一个提交button并改动Index方法,通过在文本框中输入 first name或者last name 来搜索对应的Students数据。

在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());
}

上面的代码将searchString參数加入到Index方法。你也能够向LINQ语句中加入where子句来查询那些first name 或者 last name中包括查询条件的student。

查询条件就是你所填写在Index视图的文本框中的字符串,仅仅有当文本框中由查询条件时。where语句才会运行。

注意:在非常多情况下,你能够调用不管该是Entity Framework实体集中的方法还是位于内存集合中的作为扩展的方法,得到的结果一般是一样的,可是有些情况下可能不同。

举例来说。.NET Framework实现了Contains方法,当你向该方法传递一个空字符串作为參数时,它将返回全部行,可是在SQL Server Compact 4.0的  Entity Framework提供程序中不反回不论什么行,因此上面的代码(将where语句放在if语句中)能够确保全部SQL Server版本号都能返回同样的结果。另外,.NET Framework实现的Contains方法默认是大写和小写敏感的,可是Entity Framework SQL Server 提供程序运行的比較是不区分大写和小写的。

因此。此处调用ToUpper方法来明白这里运行不区分大写和小写的比較,这样当接下来使用仓储模式时不须要改动代码就能够得到同样的结果(IEnumerable集合中的Contains方法是由
.NET Framework实现的,IQueryable对象中的Contains方法是由数据库提供程序实现的)。

对于不同的数据库提供程序或者使用IQueryable对象作比較或者使用IEnumerable集合作比較时,Null值得处理也是不同的。比如某些情况下,where条件比方table.Column !=0可能不返回那些包括null值得列。

在Student Index 视图中加入一个搜索框

打开Views\Student\Index.cshtml,加入例如以下代码

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

执行项目。输入要搜索的值,点击Search验证搜索功能是否正常

MVC5 Entity Framework学习参加排序、筛选和排序功能

注意在URL中并不包括搜索字符串,这意味着假设你将此页面增加书签,然后通过书签来打开此页面。你将无法得到筛选后的结果。

在Students Index页面中加入分页功能

要向Students Index页面中加入分页,你须要安装PagedList.Mvc NuGet包。然后你能够在Index 方法中做一些改动并在Index视图中加入分页链接。PagedList.Mvc是ASP.NET MVC中众多分页和排序包中比較好的一个。这里仅仅是使用它来作为演示,并不是作为推荐选择。

安装PagedList.Mvc NuGet包

PagedList包作为PagedList.Mvc包的依赖项会自己主动安装到项目中。PagedList包为IQueryable和IEnumable集合加入了PagedList集合类型和扩展方法。

PagedList扩展方法为从IQueryabl或IEnumable集合产生的PagedList集合数据创建了一个单一的页面。而且PagedList集合提供了多个便于分页的属性和方法。PagedList.Mvc包中含有分页帮助器并可在页面中显示分页button。

依次打开Tools-> Library Package Manager-> Package Manager Console

在打开的Package Manager Console中确保Package source是nuget.org 而且Default project是 ContosoUniversity,最后输入Install-Package PagedList.Mvc命令

MVC5 Entity Framework学习参加排序、筛选和排序功能

在Index方法中加入分页功能

打开Controllers\StudentController.cs,加入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.CurrentFiler向视图提供当前的搜索条件。该值必需要被包括在分页链接中以保证是针对搜索结果进行分页。同一时候在页面又一次显示时,搜索字符串必须显示在搜索框中。假设在分页时改动了搜索字符串。页码必需要被重置为1。由于新的搜索条件可导致不同的搜索结果。当向搜索框输入搜索字符串并点击提交button。这是searchString的值不为null。

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

在该方法的结尾部分,学生IQueryable对象的ToPagedList扩展方法将学生查询转换为一个支持分页的学生集合类型,并将该学生集合传递给视图

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

ToPagedList方法须要一个页码參数。两个问号表示空合并操作符(null-coalescing operator)。空合并操作符为nullable 类型指定默认值,表达式(page ?? 1)表示假设page值不为空就返回该值,否则返回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 class="table">
<tr>
<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>
<th></th>
</tr> @foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</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帮助器提供分页button。

在代码中使用了 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时。表单数据通过URL查询字符串来传递。这样能够同意用户将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"

PagedListPager帮助器显示分页button

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

PagedListPager帮助器提供了多个选项。你能够自己定义URL和样式

执行项目

MVC5 Entity Framework学习参加排序、筛选和排序功能

使用不同的排序方式。并点击分页button跳转至不同的页码,确保分页功能正常,然后输入查询条件,再次验证分页和搜索功能正常。

MVC5 Entity Framework学习参加排序、筛选和排序功能

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvam9obnNvbmJsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

3.创建显示学生统计信息的About页面

要让About页面显示在每个入学日共同拥有多少学生登记,须要将学生分组并进行简单的计算,要做到这些。须要运行下列操作:

  • 须要为要传递给视图的数据创建一个视图模型类
  • 改动Home控制器中的About方法
  • 改动About视图

创建视图模型

创建一个ViewModels目录并加入名为EnrollmentDataGroup.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控制器

打开HomeController.cs,在文件顶部加入using语句引入命名空间

using ContosoUniversity.DAL;
using ContosoUniversity.ViewModels;

为数据库上下文加入类变量

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

使用以下的代码替换About方法

public ActionResult About()
{
IQueryable<EnrollmentDateGroup> 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.ToList());
}

使用LINQ语句对Student实体依照enrollment date分组。计算每一个分组的实体数量,并将结果存储在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>

执行项目,点击About链接。显示学生统计信息

MVC5 Entity Framework学习参加排序、筛选和排序功能

欢迎转载,请注明文章出处:http://blog.csdn.net/johnsonblog/article/details/38795465

还大家一个健康的网络环境,从你我做起

项目源代码:https://github.com/johnsonz/MvcContosoUniversity

THE END