您的位置:首页 > 编程语言 > ASP

排序、 筛选和分页与 ASP.NET MVC 应用程序中的实体框架

2016-08-28 23:21 567 查看
http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application

Contoso 大学示例 web 应用程序演示如何创建使用实体框架 6 代码第一次和视觉工作室 2013年的 ASP.NET MVC 5 应用程序。系列教程有关的信息,请参阅本系列第一篇教程.

在前面的教程你实施一套基本的 CRUD 操作,为
Student
实体的
web 页。在本教程中,您将添加排序、 筛选和分页功能到学生索引页。您还将创建一个页面,并简单分组。

下面的插图显示页面当你完成时的外观。列标题是链接,用户可以单击要作为排序依据的列。单击列标题,一再升序和降序之间切换。




将列排序链接添加到学生索引页

若要添加排序到学生索引页面,会改变
Student
控制器的
Index
方法和
Student
索引视图中添加代码。


添加排序功能的索引方法

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


此代码接收
sortOrder
参数从
URL 中的查询字符串。由 ASP.NET MVC 作为操作方法的参数提供的查询字符串值。该参数将是一个字符串,它是"名称"日期",可以选择跟着一条下划线和字符串"desc"来指定降序排列。默认排序顺序升序。

第一次请求是索引页,那里是没有查询字符串。学生按升序排列显示的
LastName
,这是默认设置,设立的秋天通过案例
switch
语句。当用户单击列标题的超链接时,在查询字符串中提供适当
sortOrder
值。

两个
ViewBag
变量使用,查看可以配置列标题超链接与适当的查询字符串值︰
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";


这些都是三元的语句。第一个指定
sortOrder
参数为
null 或为空,是否
ViewBag.NameSortParm
应设置为"name_desc";否则,应将设置为空字符串。这两个语句启用视图,设置列标题的超链接,如下所示︰
当前排序顺序最后名称超链接日期的超链接
最后名称升序排列降序升序
最后名称降序升序升序
日期升序升序降序
日期降序升序升序
该方法使用LINQ
到实体来指定要排序的列。代码创建了一个IQueryable变量之前
switch
语句、
修改在
switch
语句,和后
switch
语句调用
ToList
方法。当您创建和修改
IQueryable
变量时,没有查询被发送到数据库。不执行查询,直到您转换
IQueryable
对象集合通过调用一个方法如
ToList
。因此,这段代码结果直到
return
View
的语句不执行单个查询中。

作为编写不同的
LINQ 语句为每个排序顺序的替代方法,您可以动态地创建 LINQ 语句。关于动态 LINQ 的信息,请参阅动态
LINQ.


添加列标题到学生索引视图的超链接

在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
属性中的信息来设置超链接与适当的查询字符串值。

运行页并单击最后一个名字和注册日期列标题,以验证该文献整理工作。



单击姓氏标题后,学生是降序显示最后一个名称。




向学生索引页添加一个搜索框

若要添加筛选到学生索引页,你会向视图中添加一个文本框和一个提交按钮和
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.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
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
子句选择只有其名字或姓氏包含搜索字符串的学生。只有在要搜索的值执行添加where子句的语句。

注意在许多情况下你可以调用同一个方法,在实体框架的实体集或作为对内存中集合的扩展方法。结果通常都是一样,但在某些情况下可能会有所不同。

例如,
Contains
方法的.NET
框架实现返回所有行,当你将一个空字符串传递给它,但 SQL Server 紧凑 4.0 的实体框架提供程序都返回零行空字符串。因此 (放
Where
if
语句的语句)
的示例中的代码将确保你得到相同的结果,所有版本的 SQL Server。而且在此基础上,
Contains
方法的.NET
框架实现默认情况下,执行区分大小写的比较,实体框架 SQL Server 提供程序在默认情况下执行不区分大小写的比较。因此,调用
ToUpper
方法使测试明确不区分大小写可以确保当您更改以后要使用存储库,它将返回而不是
IQueryable
对象
IEnumerable
集合的代码,结果不会改变。(当你调用
Contains
IEnumerable
集合时,你得到的.NET
框架实现; 当你对
IQueryable
对象调用它,你得到的数据库提供程序实现)。

空值处理也可能不同,不同的数据库供应商或当您使用
IQueryable
对象相比,当你使用
IEnumerable
集合。例如,在某些情况下一个
Where
条件如
table.Column
!= 0
可能不会返回具有
null
值的列。更多的信息,请参阅where
子句中的 null 变量的错误处理.


学生索引视图中添加一个搜索框

在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 不包含"一个"搜索字符串,这意味着,如果您收藏此页,你不会得到筛选后的列表,当您使用书签。您将更改搜索按钮,稍后在本教程中使用查询字符串进行筛选条件。


向学生索引页添加分页

要向学生索引页添加分页,你就会开始安装PagedList.Mvc NuGet
包。然后你会在
Index
法进行其他更改和添加分页链接到
Index
视图。PagedList.Mvc是一个多好的分页和排序包为
ASP.NET MVC 中,和它的使用在这里仅用作示例,不是为它在其他选项的建议。下面的插图显示分页链接。




安装 PagedList.MVC NuGet 程序包

NuGet PagedList.Mvc包自动安装PagedList软件包,作为一种依赖。PagedList包安装
IQueryable
IEnumerable
集合
PagedList
集合类型和扩展方法。扩展方法在你
IQueryable
IEnumerable
PagedList
集合中创建单个数据页和
PagedList
集合提供几个属性和便利分页的方法。PagedList.Mvc包安装一个分页的助手显示分页按钮。

从工具菜单中,选择库软件包管理器,然后程序包管理器控制台.

在程序包管理器控制台窗口中,确保 ghe软件包源是nuget.org ,默认项目是ContosoUniversity,,然后输入以下命令︰
Install-Package PagedList.Mvc




生成项目。


将分页功能添加到索引方法

在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 (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.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
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
变量将包含要显示的页面编号。

A ViewBag
属性提供的视图与当前的排序顺序,因为这必须列入分页链接以保持排序顺序在分页时相同︰
ViewBag.CurrentSort = sortOrder;


另一个属性,
ViewBag.CurrentFilter
,提供的视图的当前筛选器字符串。此值必须列入分页链接以保持筛选器设置分页,过程中,它必须将还原到文本框中时重新显示的页面。如果分页过程中更改搜索字符串,则该页面具有重置为
1,因为新的筛选器可能会导致不同的数据显示。在文本框中输入值并按提交按钮时,将改变搜索字符串。在这种情况下,
searchString
参数不是空的。
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
合并运算符。Null 合并运算符为定义了默认值为 null 的类型;该表达式
(page
?? 1)
手段返回
page
的值,如果它的值,或如果
page

null,则返回 1。


向学生索引视图添加分页链接

在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
对象。

PagedList.Mvc
using
语句,访问分页按钮的
MVC 帮手。

该代码使用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提交表单数据同一个职位,这意味着参数作为查询字符串传递
HTTP 邮件正文中,不在 URL 中。当您指定 HTTP GET 时,表单数据被通过在 URL 中作为查询字符串,使用户能够创建 URL 的书签。W3C
的 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


如果有没有要显示的页,则显示"0 0 页"。(在这种情况下页编号大于页计数因为
Model.PageNumber

1,并且
Model.PageCount
是 0)。

PagedListPager
助手显示分页按钮︰
@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )


PagedListPager
助手提供了大量的选项,您可以自定义,包括
Url 和造型。有关更多信息,请参见TroyGoode
/ PagedList GitHub 网站上。

运行页。



单击不同的排序顺序,使确定分页作品中的分页链接。然后输入搜索字符串并试分页再次来验证分页排序和过滤还可以正常工作。




创建关于显示学生统计信息的页面

为 Contoso 大学网站的网页,您将显示有多少学生为每个注册日期。这就需要对群体的分组和简单计算。要做到这一点,就会执行以下操作︰

为创建一个视图模型类的数据,您需要传递给视图。

修改
Home
控制器中的
About
方法。

修改
About
视图。


创建视图模型

在项目文件夹中创建一个Viewmodel文件夹。在该文件夹中添加一个类文件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; }
}
}


修改主控制器

在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 语句按招生日期分组学生实体、 计算每个组中的实体的数目和将结果存储在
EnrollmentDateGroup
视图模型对象的集合。

添加一个
Dispose
的方法︰
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}


修改关于视图

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>


运行应用程序并单击关于链接。学生每个招生日期的计数显示在表中。




摘要

在本教程中,您看到了如何创建一个数据模型和实现基本的 CRUD,排序、 筛选、 分页和分组功能。在接下来的教程中,您将开始看更高级的主题,通过扩展数据模型。

请留下反馈,关于如何你喜欢本教程,我们可以提高。您也可以要求在展示我如何用代码的新主题.

其他实体框架资源的链接可以找到在ASP.NET
数据访问-推荐资源.

这篇文章的初衷是在 2014 年 2 月 14 日
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐