Эффективный пейджинг ASP.NET MVC Webgrid

У меня есть проект ASP.NET MVC 4 и SQL View (vvItem). ItemController

    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 загрузит (Take()) только отображаемые записи, и он будет знать, что Skip() первые записи, если я перейду на следующие страницы.

Q: как я могу эффективно просматривать только отображаемые записи?

Я нашел 2 решения: версия JSON и NerdDinner

Я не так хорошо разбираюсь в JSON, поэтому я попробовал решение NerdDinner. И как в моей прокомментированной строке //var pageditems = itemqry.Skip(10).Take(20); itemqry уже загружен всеми записями и потребовалось много времени для загрузки.

Q2: Как я могу сделать paging сейчас? Мне нужно изменить страницу №. из метода Index.

public ActionResult Index(int? page, string filter1 = " ", string filter2 = " ")

Ответ 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

Я добавил этот sp в мою EF-модель в функции Import, чтобы он возвращал объект (vvSTOC)

    public ActionResult Index(int? page)
    {
        const int pageSize = 20;
        return View(db.spSkipTake(page, pageSize).ToList());
    }

Ответ 2

Он не должен выполнять запрос сразу, пока 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, который создается, чтобы быть уверенным.

Ответ 3

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()); 
}

Ответ 4

Спасибо за это.

Я изменил это, чтобы работать с некоторыми входными параметрами в моем SP для управления параметрами PageSize, PageNumber, SortIndex и SortOrder:

declare @sql nvarchar(1000) = '
select * from
(
    select *, row_number() over(order by '[email protected]+' '[email protected]+') as RowNumber from #Results
) as T
where T.RowNumber between ('[email protected]+' - 1) * '[email protected]+' + 1 and '[email protected]+' * '[email protected]

exec sp_executesql @sql