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.ObjectQuery 我对 ObjectQuery 不太熟悉,但听起来它在延迟执行方面表现不佳。这是令人惊讶的,因为它实现了 IQueryable 接口。我会用另一个建议更新答案。【参考方案4】:
public 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 高效分页的主要内容,如果未能解决你的问题,请参考以下文章

csharp ASP.NET MVC WebGrid列宽

使用asp.net mvc将html foreach循环数据转换为webgrid

如何在 ASP.net MVC4 上的 webgird 中绑定 JSON 返回结果值

使用 Ajax 在 ASP.NET MVC 中对 GridView 进行异步排序

ASP.Net MVC4排序检索分页的实现

csharp ASP.net MVC4分页列表