ASP.NET MVC Webgrid 高效分页
Posted
技术标签:
【中文标题】ASP.NET MVC Webgrid 高效分页【英文标题】:ASP.NET MVC Webgrid Efficient Paging 【发布时间】:2012-06-21 11:45:46 【问题描述】:我有一个 ASP.NET MVC 4 项目和一个 SQL 视图 (vvItem)。 物品控制器
MVCAppEntities db = new MVCAppEntities();
public ActionResult Index()
var itemqry = db.vvItem.OrderBy(s => s.name);
//var pageditems = itemqry.Skip(10).Take(20); // 25 seconds
return View(itemqry.ToList()); // 88 seconds
Index.cshtml 视图
@model IEnumerable<MVCApplication1.Models.vvItem>
@
var norows = 20;
var grid = new WebGrid(Model, canPage: true, rowsPerPage: norows);
grid.Pager(WebGridPagerModes.NextPrevious);
@grid.GetHtml(tableStyle: "table", headerStyle: "header", columns: grid.Columns(
grid.Column(columnName: "name", header: "Name", canSort: true),
grid.Column(columnName: "quantity", header: "Quantity", canSort: true),
grid.Column(columnName: "code", header: "Code", canSort: true),
grid.Column(columnName: "Price", header: "Price", canSort: true),
))
在 vvItem 中,我有将近 400000 条记录。我认为 webgrid Pager 只会加载 (Take()) 显示的记录,如果我要转到下一页,它会知道 Skip() 第一条记录。
问:如何有效地使视图仅加载显示的记录?
我找到了 2 个解决方案:JSON version 和 NerdDinner
我不太擅长 JSON,所以我尝试了 NerdDinner 解决方案。正如我的评论行
//var pageditems = itemqry.Skip(10).Take(20);
itemqry 已经加载了所有记录,加载需要很长时间。
Q2:我现在如何进行分页?我需要修改页码。来自 Index 方法。
public ActionResult Index(int? page, string filter1 = " ", string filter2 = " ")
【问题讨论】:
在 nerddinner 示例中,他们将在视图中实现 x 而不是 itemqry。 我将 x 重命名为 pageditems。如您所见,使用 Skip-Take 需要 25 秒,而没有 88 秒 对于问题 2,它将在控制器中进行管理,如 NerdDinner 示例和下面发布的 user1439338 所示。您的视图必须计算页面数量并管理页面链接。如 NerdDinner 链接底部所示,专用视图模型是一种好方法。 【参考方案1】:我做了一个 SQL 存储过程
CREATE PROCEDURE SkipTake
@pagNo int,
@pageSize int
AS
select *
from (select *, row_number() over (order by COD) as rn
from vvSTOC
) as T
where T.rn between (@pagNo - 1) * @pageSize + 1 and @pagNo * @pageSize
我在函数导入的 EF 模型中添加了这个 sp,以便它返回一个实体 (vvSTOC)
public ActionResult Index(int? page)
const int pageSize = 20;
return View(db.spSkipTake(page, pageSize).ToList());
【讨论】:
这是 SP 版本。如果您有其他解决方案,请填写我。 db对象是如何定义的? 我有一个 SQL 表和一个 SQL 视图(视图显示来自这个表的行加上来自另一个表的一些不重要的数据(~ 1000 条记录))有 ~ 400.000 条记录。您想查看视图和表中的 SQL 脚本吗? 不,你在上面回答了我的问题,我想我现在明白了。 @Misi 你能解释一下这是如何在视图中显示的/如何在视图中显示分页结果(当我们以 SP 方式进行时)??【参考方案2】:谢谢。
我对此进行了调整,以使用我的 SP 中的一些输入参数来控制 PageSize、PageNumber、SortIndex 和 SortOrder:
declare @sql nvarchar(1000) = '
select * from
(
select *, row_number() over(order by '+@SortIndex+' '+@SortOrder+') as RowNumber from #Results
) as T
where T.RowNumber between ('+@PageNumber+' - 1) * '+@PageSize+' + 1 and '+@PageNumber+' * '+@PageSize
exec sp_executesql @sql
【讨论】:
【参考方案3】:只要 itemqry 是 IEnumerable 或 IQueryable 类型,它就不应立即执行查询。您可以将其转换为 IQueryable,如下所示?
public ActionResult Index()
IQueryable<vvItem> itemQry = db.vvItem;
return View(itemQry.OrderBy(s => s.name).Skip(10).Take(20).ToList());
如果 itemqry 是正确的类型,则在调用 .ToList() 将其转换为 IList 类型之前,它不会被执行。检查正在生成的 SQL 以确保确定。
【讨论】:
你在我回来的评论行中写下了我的内容。我在没有 Skip() 和 Take() 的情况下计时了 1 分半钟,使用 Skip() 和 Take() 计时了 25 秒。在 SQL 中,从同一张表中,如果我写 TOP 1000,它将在 1 秒内返回 1000 行 如果在 Visual Studio 中将鼠标悬停在 itemqry 上,它是什么类型的变量? System.Data.Objects.ObjectQuerypublic ActionResult Index(int? pageIndex)
int pageSize = 20;
var itemIndex = ((pageIndex??1) -1) * pageSize;
return View(db.vvItem.OrderBy(s => s.name).Skip(itemIndex).Take(pageSize).ToList());
【讨论】:
以上是关于ASP.NET MVC Webgrid 高效分页的主要内容,如果未能解决你的问题,请参考以下文章
使用asp.net mvc将html foreach循环数据转换为webgrid
如何在 ASP.net MVC4 上的 webgird 中绑定 JSON 返回结果值