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

61 篇文章 1 订阅
45 篇文章 0 订阅

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 页。在本教程中,您将添加排序、 筛选和分页功能到学生索引页。您还将创建一个页面,并简单分组。

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

Students_Index_page_with_paging

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

若要添加排序到学生索引页面,会改变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属性中的信息来设置超链接与适当的查询字符串值。

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

Students_Index_page_with_sort_hyperlinks

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

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

若要添加筛选到学生索引页,你会向视图中添加一个文本框和一个提交按钮和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 的实体框架提供程序都返回零行空字符串。因此 (放Whereif语句的语句) 的示例中的代码将确保你得到相同的结果,所有版本的 SQL Server。而且在此基础上, Contains方法的.NET 框架实现默认情况下,执行区分大小写的比较,实体框架 SQL Server 提供程序在默认情况下执行不区分大小写的比较。因此,调用ToUpper方法使测试明确不区分大小写可以确保当您更改以后要使用存储库,它将返回而不是IQueryable对象IEnumerable集合的代码,结果不会改变。(当你调用ContainsIEnumerable集合时,你得到的.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>

运行页,输入搜索字符串,并单击搜索,筛选验证正常工作。

Students_Index_page_with_search_box

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

向学生索引页添加分页

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

Students_index_page_with_paging

安装 PagedList.MVC NuGet 程序包

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

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

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

Install-Package PagedList.Mvc

Install 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.Mvcusing语句,访问分页按钮的 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 网站上。

运行页。

Students_index_page_with_paging

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

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

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

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

About_page

摘要

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

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

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

这篇文章的初衷是在 2014 年 2 月 14 日

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值