现在我将模型中的列表返回到视图中。该清单包含300k项目。
我正在做这样的事情
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>E-mail</th>
<th>Role</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model) {
<tr>
<td>@user.FirstName</td>
<td>@user.LastName</td>
<td>@user.Email</td>
<td>@user.UserRole.UserRoleName</td>
</tr>
}
</tbody>
</table>
因此,问题是加载页面以显示300k项目需要永远,加上所有滚动都是一个问题。在MVC中是否有更好的解决方案来处理这个并添加自动分页等?
答案 0 :(得分:4)
有许多解决方案可以帮助你但棘手的部分是没有人会完全解决它。
我所说的是,他们会帮助客户端,使用分页组件和网格来显示数据,甚至可以使用无限滚动(例如Facebook时间,根据需要加载N个更多的recods) 。有些人也会在服务器端帮助你。
但由于它与您的数据源和数据结构太相关,因此没有&#34;对所有情况有效&#34;溶液
我有大约10个生产阶段的大型ASP.NET MVC项目,而不是每个项目都使用相同的技术。他们中的大多数使用jQuery DataTables,它是一个整合的jquery插件,可以帮助您完成很多事情,包括排序,过滤,当然还有服务器端分页。在我的回答的最后,您将找到一些指向DataTables和我在GitHub上的项目的链接,它可以帮助提供服务器端以及其他一些有趣的链接。
最近我们转向Angular(来自Google团队)。它有一个内置的网格机制(你可以使用其他人,如果你愿意的话),称为ngGrid,它还可以进行分页,过滤和排序。
将代码视为&#34;动作模板&#34;,它可以帮助您开始服务器端分页(我假设您为了使用EF而使用EF)这个样本):
public JsonResult Paginate(int page, int recordsPerPage, string filter, string[] sorting)
{
// 1. count total (non-filtered) data from your database.
var _total = context.Entities.Count();
// 2. count filtered (available) record set
var _filtered = context.Entities.Where(_e => _e.Description.ToLower().Contains(filter)).Count();
// 3. retrieve only desired page, here follows some linq sample if you're using EF
// I'm assuming your page count starts with 1 (natural counting), that's why I'm subtracting
// one from the current page number
var _page = context.Entities.Where(_e => _e.Description.ToLower().Contains(filter)).OrderBy(_e => _e.Description).Skip((page - 1) * recordsPerPage).Take(recordsPerPage);
// 4. Return a json object (or view result with all counters and data to display)
return Json(new { TotalRecords = total, FilteredRecords = filtered, Records = _page });
}
请记住,为了方便起见,我没有处理排序集合。当然,您应该这样做,因此您的最终用户可以轻松地对所有数据进行排序。
现在,从您的客户端,您将以类似于以下的方式请求(ajax,我建议,仅提取必要的数据):
<script>
$.ajax({
url: "/my/route",
data: { page: _page, recordsPerPage: _recordsPerPage, filter: _filter, sorting: _sorting },
method: "POST",
success: function(jsonResult) { /* update your data on grid/table/div/etc */ },
error: function(errorResult) { console.log(errorResult); /* temporary, so you may find out what happened*/ }
});
</script>
请注意,_page
是一个变量,您可以在其中找到&#34; next-desired-page&#34;,它可以是第一页,上一页,下一页,最后一页或特定页面(大多数)常见情况),_recordsPerPage
是一个变量,当用户从下拉列表中选择较大(或较小)的页面大小时,该变量可能会发生变化,_filter
是一个在{上更新的字符串' {1}} blur
和text-input
的事件是您的商店需要排序的字符串数组。
USUALLY 插件(如DataTables,jqGrid等)将为您填充这些变量,或者为您提供获取这些变量的方法。
作为可用性的一般规则,从不为最终用户返回超过20条记录,除非他/她明确另有说明(例如:通过从下拉列表中选择每页记录值) )。您将避免数据库中不必要的负载,不必要的链接消耗,并且您的页面加载速度会快得多。
我提出的另一个建议是为您的分页创建一个帮助程序类,以便您始终拥有一个标准,例如:
_sorting
通过这种方式,无论页面返回的实体类型如何,您都可以创建某种通用的局部视图来显示数据。
但所有这些都可能会根据您使用的内容而改变。例如,如果您使用纯public class PageViewModel<TEntity>
{
public int TotalCount { get; private set; }
public int FilteredCount { get; private set; }
public IEnumerable<TEntity> Records { get; private set; }
public int RecordsPerPage { get; private set; }
// Help with some jQuery libs to help counting the number of pages to display...
public int AvailablePages { get; private set; }
/* Constructor */
}
,则必须为相同的SKIP / TAKE方法处理不同的SQL语法,并且该实现可能会从DB版本更改。 2008年之前的MSSQL不会帮助您进行分页。
如果您正在使用ADO.NET
(这是StackOverflow下的ORM),您可以编写分页SQL或使用扩展名,例如Dapper
,DapperExtensions
或者Rainbow
,这将有助于使用花哨的分页方法,而不需要所有SQL语法的东西。
如果你进入EF,你只需使用Dapper.Contrib
即可。根据我对NHibernate的了解(从未实际使用过),应与LinqToEntities
类似。
此外,如果您使用(或不使用)存储库,则可能会发生变化。在您看来,您的控制器可能只是以集中的方式将页面解析和记录提取委托给您的存储库。如果没有,你最终会得到大量重复的代码或许多帮助者。
但如果您 不能使用javascript,那么您可以使用常规ASP.NET MVC来完成所有操作。你会有更多的工作,但是,这是可能的。
无论如何,这里有一些链接可以帮助你:
答案 1 :(得分:0)
我发现当数据集太大时,后端和前端都只能获取渲染总数据集子集所需的数据。在LINQ中,它将是一个.Skip。获取所需的分页数据。
答案 2 :(得分:0)
虽然@ marcusking2002提供的答案是正确的,但有许多功能齐全的jQuery网格组件可以为您的用户提供更丰富的用户体验,并为您节省大量的手动格式。
这些包括jqGrid http://www.trirand.com/blog/,flexigrid http://www.flexigrid.info/(免费选项),或者如果您想要收取一些现金,那么剑道的http://www.telerik.com/kendo-ui提供的功能非常强大。
还有其他人,这些只是我使用的那些:)