Home > Back-end >  LINQ query to order elements between two variables
LINQ query to order elements between two variables

Time:09-29

a complete beginner here.
I am trying to create a JSONResult which I am trying to get to return between two variables. Here is the action:

public JsonResult GetVoices(int? PageNumber, int? PageSize)
        {
            var StartRow = ((PageNumber - 1) * PageSize)   1;
            var EndRow = PageNumber * PageSize;
            var i = 0;
            var data = (from a in db.Content
                        select new
                        {
                            RowNumber = i  ,
                            Id = a.Id,
                            Title = a.Title,
                            Description = a.Description,
                            CreatedAt = a.CreatedAt
                        }).ToList();
            return Json(data, JsonRequestBehavior.AllowGet);
        }

As you can see there are two parameters which eventually specify the Row to start from and end from. I want all the RowNumber returned to be between StartRow and LastRow

CodePudding user response:

So you have a PageSize and a PageNumber, and you want all rows that are on the page with PageNumber.

  • Page [0] contains rows 0 to PageSize - 1
  • Page 1 contains rows PageSize to 2*PageSize - 1
  • Page [2] contains rows 2PageSize to 3PageSize - 1
  • etc.

This seems to be a very common problem, so let's not limit ourselves to a solution for this problem only, let's make a solution suitable for all sequences that needs to be divided into pages.

My advice would be to create an extension method of IQueryable<T>, so you can intertwine the pagination with other LINQ methods. If you are not familiar with extension methods, consider to read Extension Methods Demystified

Input: a sequence of similar items: IQueryable<T>, a PageSize and a PageNumber.

Output: all rows on page PageNumber, according to the definition above. So each page, except the last one has PageSize number of rows. The last Page will have Total number of rows % PageSize

I decided to return IQueryable<T>, not ICollection<T>. This has the advantage that if you don't enumerate the rows on a page, the data is not fetched. The disadvantages is that you have to calculate the number of rows on each page, and the number of pages. If you think you will always enumerate all rows on all pages, consider to return ICollection<T>.

public IQueryable<T>> FetchPage<T>(
    this IQueryable<T> source,
    int pageNumber,
    int pageSize)
{
    // TODO: check input parameters: source not null, pageSize > 0,
    // pageNumber >= 0

    return source.Skip(pageNumber * pageSize)
                 .Take(pageSize);
}

Usage: if you have a table of Products, and you want to divide this into Pages of size 25, and you want to fetch Page 3, with the cheapest Products first:

IQueryable<Product> productsOnPage3 = dbContext.Products
    .OrderBy(product => product.Price)
    .FetchPage(3, 25)
    .ToList();

If you don't want the complete row on your pages, you can add a Select.

Consider to create extension methods with parameters selector like in LINQ Select:

public IQueryable<T>> FetchPage<T>(
    this IQueryable<T> source,
    int pageNumber,
    int pageSize,
    Expression<Func<TSource,TResult>> selector)
{
    // TODO: check input parameter selector

    return source.FetchPage(pageNumber, pageSize)
                 .Select(selector);
}

And maybe also an overload with a sortKey.

CodePudding user response:

You're looking for something like this:

public JsonResult GetVoices(int PageNumber, int PageSize) =>
    Json((from a in db.Content.ToArray()
         let StartRow = ((PageNumber - 1) * PageSize)   1
         let EndRow = PageNumber * PageSize
         from RowNumber in Enumerable.Range(StartRow, EndRow - StartRow   1)
         select new
         {
             RowNumber = RowNumber,
             Id = a.Id,
             Title = a.Title,
             Description = a.Description,
             CreatedAt = a.CreatedAt
         }).ToList(), JsonRequestBehavior.AllowGet);
  • Related