排序甩十、過(guò)濾、分頁(yè)吭产、分組
Contoso 大學(xué)示例 Web 應(yīng)用程序演示如何使用實(shí)體框架(EF)Core 2.0 和 Visual Studio 2017 創(chuàng)建 ASP.NET Core 2.0 MVC Web 應(yīng)用程序侣监。 如欲了解更多本教程相關(guān)信息,請(qǐng)參閱 入門
在前面的教程臣淤,你實(shí)現(xiàn)了一組 Student 實(shí)體的基本 CRUD 頁(yè)面橄霉。 在本節(jié)中,您將向 Student 列表頁(yè)添加排序邑蒋、 篩選和分頁(yè)功能姓蜂, 還將創(chuàng)建一個(gè)進(jìn)行簡(jiǎn)單分組的頁(yè)面。
下圖顯示本節(jié)中將會(huì)完成的頁(yè)面医吊。 用戶可以點(diǎn)擊列標(biāo)題進(jìn)行排序钱慢。 重復(fù)點(diǎn)擊列標(biāo)題將排序在升序和降序之間切換。
將列排序鏈接添加到學(xué)生索引頁(yè) (Student Index)
要在學(xué)生索引頁(yè)中添加排序卿堂,需要更改 Students 控制器中的 Index 的方法束莫,并添加代碼到 Students Index 視圖。
在 Index 方法中添加排序功能
在 StudentsController.cs草描,替換 Index 方法為以下代碼:
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.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(await students.AsNoTracking().ToListAsync());
}
代碼從 URL 中接收 sortOrder 查詢參數(shù)览绿,此查詢參數(shù)由 ASP.NET Core MVC 提供。參數(shù)是值為 "Name" 或 "Date" 的字符串穗慕,有時(shí)候后面會(huì)帶有下劃線和字符串 "desc" 來(lái)指定降序順序饿敲。 默認(rèn)排序順序?yàn)樯颉?br>
第一次請(qǐng)求索引頁(yè)時(shí),沒(méi)有附加查詢字符串逛绵。 在默認(rèn)的 Switch default 方法中按 LastName 排序诀蓉。 當(dāng)用戶單擊列標(biāo)題栗竖,相應(yīng)的 sortOrder 將會(huì)出現(xiàn)在查詢字符串中。
兩個(gè) ViewData 元素 ( NameSortParm 和 DateSortParm )供視圖用于配置列標(biāo)題超鏈接查詢字符串渠啤。
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
當(dāng)前排序情況 | LastName 鏈接 | Date 鏈接 |
---|---|---|
LastName 升序 | 降序 | 升序 |
LastName 降序 | 升序 | 升序 |
Date 升序 | 升序 | 降序 |
Date 降序 | 升序 | 升序 |
這是三元選擇語(yǔ)句狐肢。 如果 sortOrder 參數(shù)為 null 或?yàn)榭眨琋ameSortParm 應(yīng)設(shè)置為 "name_desc"; 否則沥曹,設(shè)置為一個(gè)空字符串份名。 這兩個(gè)語(yǔ)句在視圖中用于設(shè)置列標(biāo)題超鏈接,如下所示:
當(dāng)前排序情況 | LastName 鏈接 | Date 鏈接 |
---|---|---|
LastName 升序 | 降序 | 升序 |
LastName 降序 | 升序 | 升序 |
Date 升序 | 升序 | 降序 |
Date 降序 | 升序 | 升序 |
方法中使用 LINQ to Entities 指定排序列妓美。 在進(jìn)行 Switch 判斷前僵腺, 創(chuàng)建 IQueryables 變量, 在判斷之后壶栋, 調(diào)用 ToListAsync 方法辰如。 在創(chuàng)建和修改 IQueryable 變量過(guò)程中,查詢并不會(huì)真正發(fā)送到數(shù)據(jù)庫(kù)贵试,直到你通過(guò)調(diào)用一個(gè)類似 ToListAsync 的方法將 IQueryable 變量轉(zhuǎn)化為一個(gè)集合琉兜。 因此,在這段代碼中毙玻,只當(dāng)返回 View 語(yǔ)句執(zhí)行時(shí)豌蟋,查詢才真正發(fā)生。
這樣的代碼可能導(dǎo)致出現(xiàn)非常多的列變量桑滩,在本系列最后一個(gè)教程中將告訴你如何在變量中傳遞排序列名梧疲。
在學(xué)生索引視圖中添加列標(biāo)題超鏈接
為了添加列標(biāo)題超鏈接,替換 Views/Students/Index.cshtml 文件中的代碼為如下代碼:
<th>
<a asp-action="Index" asp-route-sortOrder = "@ViewData["NameSortParm"]"> @Html.DisplayNameFor(model => model.LastName) </a>
</th>
<th>
@Html.DisplayNameFor(model => model.FirstMidName)
</th>
<th>
<a asp-action="Index" asp-route-sortOrder = "@ViewData["DateSortParm"]"> @Html.DisplayNameFor(model => model.EnrollmentDate) </a>
</th>
代碼使用 ViewData 屬性中的信息建立超鏈接中的查詢字符串运准。
運(yùn)行應(yīng)用程序中幌氮,選擇 Student 菜單,然后單擊 Last name 和 Enrollement Date 列標(biāo)題胁澳,以驗(yàn)證排序是否生效该互。
在學(xué)生索引視圖中添加搜索框
要在學(xué)生索引頁(yè)面中添加過(guò)濾功能,您需要在視圖中添加一個(gè)文本框和一個(gè)提交按鈕听哭,并在 Index 方法中做相應(yīng)修改慢洋。 文本框中塘雳,你將輸入要在名字和姓氏字段中搜索的字符串陆盘。
在 Index 方法中添加過(guò)濾功能
在StudentsController.cs,替換 Index 方法替換為以下代碼
public async Task<IActionResult> Index(string sortOrder, string searchString)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.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(await students.AsNoTracking().ToListAsync());
}
在 Index 方法中添加 searchString 參數(shù)败明,此參數(shù)值來(lái)自剛剛加入視圖中的文本框隘马。同時(shí),在 LINQ 語(yǔ)句中添加一個(gè) Where 子句來(lái)選擇名字 (first name 和 last name)中包含查詢字符串的學(xué)生妻顶。Where 子句僅當(dāng)查詢字符串中有值時(shí)才生效酸员。
備注
在這里蜒车, 您在 IQueryable 對(duì)象上調(diào)用 Where 方法, 過(guò)濾將在服務(wù)器上進(jìn)行幔嗦。某些情況下酿愧,您也可能是對(duì)內(nèi)存集合調(diào)用 Where 方法。(例如邀泉,假設(shè)你將 _context.Students 的引用嬉挡,從 EF Dataset 修改為一個(gè)返回 IEnumerable 的倉(cāng)儲(chǔ)方法。)查詢結(jié)果通常是相同的汇恤,但在某些情況下可能會(huì)有所不同庞钢。
例如,.NET Framework 實(shí)現(xiàn)的 Contains 方法默認(rèn)區(qū)分大小寫因谎。但 SQL Server 中這取決于 SQL Server 實(shí)例的排序規(guī)則設(shè)置基括,該設(shè)置默認(rèn)為不區(qū)分大小寫。 您可以調(diào)用 ToUpper 來(lái)進(jìn)行測(cè)試顯式不區(qū)分大小寫的方法:Where (s = > s.LastName.ToUpper()财岔。Contains(searchString.ToUpper())
风皿。 這將確保如果稍后你修改代碼為使用返回 IEnumerable 對(duì)象的倉(cāng)儲(chǔ) Repository,而不是返回 IQueryable 對(duì)象時(shí)使鹅,結(jié)果保持相同揪阶。 (當(dāng)您在 IEnumerable 集合上調(diào)用 Contains 方法時(shí),使用的是 .NET Framework 實(shí)現(xiàn); 而在 IQueryable 對(duì)象上患朱,則使用 database provider 實(shí)現(xiàn)鲁僚。) 但是,這個(gè)解決方案將對(duì)性能產(chǎn)生負(fù)面影響裁厅。ToUpper
代碼將在 TSQL 查詢語(yǔ)句的 Where 條件中加入函數(shù)調(diào)用冰沙,進(jìn)而導(dǎo)致 SQL 優(yōu)化器停止使用索引。 假設(shè) SQL 主要安裝為不區(qū)分大小寫执虹,最好是避免 ToUpper 代碼拓挥,直到您遷移到區(qū)分大小寫的數(shù)據(jù)存儲(chǔ)區(qū)。
在 Index 視圖中添加搜索框
在Views/Student/Index.cshtml袋励,在 <Table>
標(biāo)簽前加入如下代碼侥啤,創(chuàng)建一個(gè)標(biāo)題、一個(gè)文本框和一個(gè)搜索按鈕茬故。
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
代碼使用 <form>
標(biāo)簽盖灸,添加搜索文本框和按鈕。默認(rèn)情況下磺芭,<form>
標(biāo)簽使用 POST
方法進(jìn)行數(shù)據(jù)提交赁炎,參數(shù)在消息正文而不是 URL 查詢字符串中傳遞。通過(guò)指定使用 GET
方法钾腺,窗體數(shù)據(jù)通過(guò) URL 查詢字符串進(jìn)行傳遞徙垫,這是的用戶可以對(duì) URL 創(chuàng)建書簽讥裤。 W3C 準(zhǔn)則建議,在未導(dǎo)致更新的操作中姻报,使用 GET
方法己英。
運(yùn)行應(yīng)用程序中,選擇 Student 菜單吴旋,輸入任意搜索字符剧辐,并點(diǎn)擊“搜索”按鈕,以驗(yàn)證過(guò)濾功能生效邮府。
請(qǐng)注意在 URL 中包含了搜索字符串荧关。
http://localhost:5813/Students?SearchString=an
如果您將本頁(yè)面加入書簽,下次使用書簽時(shí)褂傀,您將得到過(guò)濾后的列表忍啤。在 Form
標(biāo)簽中添加的 method="get"
是產(chǎn)生查詢字符串的原因。
在此階段仙辟,如果您單擊列標(biāo)題進(jìn)行排序同波,你將丟失搜索框中輸入的過(guò)濾查詢。 在下一部分中將修復(fù)此問(wèn)題叠国。
在學(xué)生索引視圖中添加分頁(yè)功能
要在學(xué)生索引頁(yè)中添加分頁(yè)功能未檩,您將創(chuàng)建一個(gè) PaginatedList
類,在類中使用 Skip
和 Take
語(yǔ)句實(shí)現(xiàn)在服務(wù)器過(guò)濾數(shù)據(jù)粟焊,而不是獲取數(shù)據(jù)表的所有數(shù)據(jù)行冤狡。然后再對(duì) Index
做一些更改,再 Index
視圖中添加分頁(yè)按鈕项棠。下圖中展示了分頁(yè)按鈕悲雳。
在項(xiàng)目文件夾中,創(chuàng)建
PaginatedList.cs
香追,然后鍵入下面的代碼合瓢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity
{
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
this.AddRange(items);
}
public bool HasPreviousPage
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (PageIndex < TotalPages);
}
}
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(items, count, pageIndex, pageSize);
}
}
}
代碼中,CreateAsync
方法獲取分頁(yè)大小及頁(yè)碼透典,再 IQueryable
對(duì)象上使用相應(yīng)的 Skip
和 Take
語(yǔ)句晴楔。 在 IQueryable
上調(diào)用 ToListAsync
后, 返回一個(gè)只包含請(qǐng)求頁(yè)的列表峭咒。 屬性 HasPreviousPage
及 HasNextPage
用于啟用或禁用 “上一頁(yè)” 和 “下一頁(yè)” 按鈕税弃。
在 PaginatedList<T>
中使用 CreateAsync
方法而不是構(gòu)造函數(shù)的原因是構(gòu)造函數(shù)無(wú)法運(yùn)行異步代碼。
ACreateAsync方法用于而不是一個(gè)構(gòu)造函數(shù)創(chuàng)建PaginatedList<T>對(duì)象讹语,因?yàn)闃?gòu)造函數(shù)不能運(yùn)行異步代碼钙皮。
在 Index
方法中添加分頁(yè)功能
在 StudentsController.cs
蜂科,替換 Index
方法替換為以下代碼顽决。
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? page)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.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;
}
int pageSize = 3;
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), page ?? 1, pageSize));
}
代碼在方法中添加了 page, sortOrder, currentFilter 三個(gè)參數(shù)短条。
第一次顯示頁(yè)面,或如果用戶未單擊分頁(yè)或排序鏈接才菠,則所有參數(shù)將都為 null
茸时。 單擊分頁(yè)鏈接時(shí),如果頁(yè)變量將包含要顯示的頁(yè)碼赋访。
ViewData("CurrentSort") 保存當(dāng)前排序以供視圖使用可都。在視圖的分頁(yè)鏈接中包含排序,翻頁(yè)的時(shí)候才能保持排序不變蚓耽。
ViewData("CurrentFilter")保存當(dāng)前過(guò)濾字符串以供視圖使用渠牲。在視圖的分頁(yè)鏈接中包含過(guò)濾字符串,翻頁(yè)額時(shí)候才能保持過(guò)濾不變步悠。
如果在分頁(yè)期間签杈,搜索字符串被更改,因?yàn)樾碌倪^(guò)濾導(dǎo)致顯示不同的數(shù)據(jù)鼎兽,頁(yè)碼必須被重置為第一頁(yè)答姥。在文本框中輸入并按下提交按鈕時(shí),搜索字符串改變谚咬。在這種情況下鹦付,searchString 參數(shù)不為空。
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
在 Index
方法結(jié)尾择卦, PaginatedList.CreateAsync
方法轉(zhuǎn)化學(xué)生查詢至一個(gè)支持分頁(yè)功能的單頁(yè)學(xué)生集合敲长,然后這個(gè)集合被傳遞給視圖。
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), page ?? 1, pageSize));
PaginatedList.CreateAsync
方法使用參數(shù) page
(頁(yè)碼)和pageSize
(頁(yè)大斜獭)作為參數(shù)潘明。 page
參數(shù)后的兩個(gè) ?
代表 null 合并運(yùn)算符
。null 合并運(yùn)算符
定義了可為空類型的默認(rèn)值秕噪;page ?? 1
表達(dá)式意味著钳降,如果 page
具有一個(gè)值(不為空),則返回 page
腌巾, 如果為空則返回 1
遂填。
在 Index
視圖中添加分頁(yè)鏈接
在 Views/Students/Index.cshtml
,替換為以下代碼澈蝙。
@model PaginatedList<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Last Name</a>
</th>
<th>
First Name
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Enrollment Date</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@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>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@{
var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.HasNextPage ? "disabled" : "";
}
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-page="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-page="@(Model.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @nextDisabled">
Next
</a>
譯者注:Markdown 語(yǔ)法無(wú)法實(shí)現(xiàn)代碼內(nèi)高亮吓坚,如不清楚修改的位置,請(qǐng)參考微軟原文灯荧。
頁(yè)面頂部的 @model
指定視圖現(xiàn)在獲取 PaginatedList<T>
對(duì)象而不是 List<T>
對(duì)象礁击。
列標(biāo)題上的鏈接使用查詢字符串將當(dāng)前的搜索字符串傳遞到控制器,以便用戶可以在過(guò)濾后的結(jié)果中進(jìn)行排序:
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter ="@ViewData["CurrentFilter"]">Enrollment Date</a>
The paging buttons are displayed by tag helpers:
分頁(yè)按鈕使用 tag helpers
進(jìn)行顯示
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-page="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
運(yùn)行應(yīng)用并轉(zhuǎn)到 Student 頁(yè)面。
在不同排序狀態(tài)下點(diǎn)擊分頁(yè)鏈接哆窿,以確認(rèn)分頁(yè)功能正常工作链烈。然后嘗試搜索后再分頁(yè),驗(yàn)證分頁(yè)功能在不同排序和過(guò)濾條件下都正常工作挚躯。
創(chuàng)建一個(gè)顯示學(xué)生統(tǒng)計(jì)信息的關(guān)于頁(yè)面
在 Contoso 大學(xué)網(wǎng)站的 About
頁(yè)面强衡, 將顯示每天有多少學(xué)生進(jìn)行注冊(cè),這需要對(duì)數(shù)據(jù)進(jìn)行分組码荔,并在分組上做計(jì)算漩勤。要完成此任務(wù),您需要執(zhí)行以下操作:
- 創(chuàng)建一個(gè)用于傳遞數(shù)據(jù)到視圖的 ViewModel 類缩搅。
- 修改
HomeController
中的About
方法越败。 - 修改
About
視圖。
創(chuàng)建 ViewModel 類
在 Models
文件夾中創(chuàng)建一個(gè) SchoolViewModels
文件夾
在這個(gè)新的文件夾中硼瓣,添加一個(gè)文件名為 EnrollmentDateGroup.cs
的類眉尸,并輸入以下代碼:
using System;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.Models.SchoolViewModels
{
public class EnrollmentDateGroup
{
[DataType(DataType.Date)]
public DateTime? EnrollmentDate { get; set; }
public int StudentCount { get; set; }
}
}
修改 HomeController
在 HomeController.cs
文件, 頂部加入如下語(yǔ)句:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models.SchoolViewModels;
在類中添加一個(gè)數(shù)據(jù)庫(kù)上下文變量 _context, ASP.NET Core 依賴注入將為此變量提供實(shí)例巨双。
public class HomeController : Controller
{
private readonly SchoolContext _context;
public HomeController(SchoolContext context)
{
_context = context;
}
將 About 方法替換為以下代碼:
public async Task<ActionResult> About()
{
IQueryable<EnrollmentDateGroup> data =
from student in _context.Students
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
return View(await data.AsNoTracking().ToListAsync());
}
LINQ 語(yǔ)句將 Student 實(shí)體進(jìn)行分組噪猾,計(jì)算每個(gè)分組中的實(shí)體數(shù)量,并將結(jié)果存放在 EnrollmentDateGroup
ViewModel 對(duì)象中筑累。
備注
在 EF Core 1.0 版本中袱蜡, 整個(gè)結(jié)果集返回到客戶端,并在客戶端上進(jìn)行分組慢宗。在某些情況下坪蚁,這會(huì)導(dǎo)致性能問(wèn)題。請(qǐng)使用實(shí)際生產(chǎn)環(huán)境規(guī)模的數(shù)據(jù)測(cè)試性能镜沽,如有必要敏晤,使用原始 SQL 在服務(wù)器進(jìn)行分組。 有關(guān)如何使用原始的 SQL 的信息缅茉,請(qǐng)參閱本系列最后一個(gè)教程嘴脾。
修改 About
視圖
替換 Views/Home/About.cshtml 為如下代碼:
@model IEnumerable<ContosoUniversity.Models.SchoolViewModels.EnrollmentDateGroup>
@{
ViewData["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>
運(yùn)行應(yīng)用,轉(zhuǎn)至 About 頁(yè)面蔬墩。 每個(gè)日期的學(xué)生注冊(cè)數(shù)量顯示于表格中译打。
小結(jié)
在本教程中,你已了解如何執(zhí)行排序拇颅、 篩選奏司、 分頁(yè)和分組。 在下一步的教程中樟插,你將了解如何通過(guò)使用遷移來(lái)處理數(shù)據(jù)模型更改韵洋。