Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add Pagination MVC and Azure table storage

Iam trying to apply Pagination to my MVC application. Iam using Azure table storage

Here is what I have tried:-

public List<T> GetPagination(string partitionKey, int start, int take)
    {
        List<T> entities = new List<T>();

        TableQuery<T> query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey.ToLower()));
        entities = Table.ExecuteQuery(query).Skip(start).Take(take).ToList();

        return entities;

    }

Controller:-

public ActionResult Index()
        {

            key= System.Web.HttpContext.Current.Request[Constants.Key];
            if (String.IsNullOrEmpty(key))
                return RedirectToAction("NoContext", "Error");

            var items= _StorageHelper.GetPagination(key,0,3);
           ItemCollection itemCollection = new ItemCollection();
            itemCollection .Items= Mapper.Map<List<ItemChart>, List<ItemModel>>(items);
            itemCollection .Items.ForEach(g => g.Object = g.Object.Replace(key, ""));


            return View(itemCollection);
        }

This currently gives me the first 3 entries from my data. Now how can I show and implement the "Previous" and "Next" to show the rest of the entries on next page? How do I implement the rest of the controller and HTML page?

Any help is appreciated.

like image 954
HappyCode1990 Avatar asked Feb 19 '15 05:02

HappyCode1990


1 Answers

When it comes to pagination, there are a few things to consider:

  • Not all LINQ operators (and in turn OData query options) are supported for Table Service. For example Skip is not supported. For a list of supported operators, please see this link: https://msdn.microsoft.com/en-us/library/azure/dd135725.aspx.
  • The way pagination works with Table Service is that when you query your table to fetch some data, maximum number of entities that can be returned by table service is 1000. There's no guarantee that always 1000 entities will be returned. It may be less than 1000 or even 0 depending on how you're querying. However if there are more results available, Table Service returns something called a Continuation Token. You must use this token to fetch next set of results from table service. Please see this link for more information on query timeout and pagination: https://msdn.microsoft.com/en-us/library/azure/dd135718.aspx.

Taking these two factors into consideration, you can't really implement a paging solution where a user can directly jump to a particular page (for example, user is sitting on page 1 and then the user can't go to page 4). At the most you can implement next page, previous page and first page kind of functionality.

To implement next page kind of functionality, store the continuation token returned by table service and use that in your query.

To implement previous page kind of functionality, you must store all the continuation tokens returned in an array or something and keep track of which page a user is on currently (that would be the current page index). When a user wants to go to previous page, you just get the continuation token for the previous index (i.e. current page index - 1) and use that in your query.

To implement first page kind of functionality, just issue your query without continuation token.

Do take a look at ExecuteQuerySegmented method in Storage Client Library if you want to implement pagination.

UPDATE

Please see the sample code below. For the sake of simplicity, I have only kept first page and next page functionality:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using Microsoft.WindowsAzure.Storage.Table;
namespace TablePaginationSample
{
    class Program
    {
        static string accountName = "";
        static string accountKey = "";
        static string tableName = "";
        static int maxEntitiesToFetch = 10;
        static TableContinuationToken token = null;
        static void Main(string[] args)
        {
            var cloudStorageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
            var cloudTableClient = cloudStorageAccount.CreateCloudTableClient();
            var table = cloudTableClient.GetTableReference(tableName);
            Console.WriteLine("Press \"N\" to go to next page\nPress \"F\" to go first page\nPress any other key to exit program");
            var query = new TableQuery().Take(maxEntitiesToFetch);
            var continueLoop = true;
            do
            {
                Console.WriteLine("Fetching entities. Please wait....");
                Console.WriteLine("-------------------------------------------------------------");
                var queryResult = table.ExecuteQuerySegmented(query, token);
                token = queryResult.ContinuationToken;
                var entities = queryResult.Results;
                foreach (var entity in entities)
                {
                    Console.WriteLine(string.Format("PartitionKey = {0}; RowKey = {1}", entity.PartitionKey, entity.RowKey));
                }
                Console.WriteLine("-------------------------------------------------------------");
                if (token == null)//No more token available. We've reached end of table
                {
                    Console.WriteLine("All entities have been fetched. The program will now terminate.");
                    break;
                }
                else
                {
                    Console.WriteLine("More entities available. Press \"N\" to go to next page or Press \"F\" to go first page or Press any other key to exit program.");
                    Console.WriteLine("-------------------------------------------------------------");
                    var key = Console.ReadKey();
                    switch(key.KeyChar)
                    {
                        case 'N':
                        case 'n':
                            continue;
                        case 'F':
                        case 'f':
                            token = null;
                            continue;
                        default:
                            continueLoop = false;
                            break;
                    }
                }
            } while (continueLoop);
            Console.WriteLine("Press any key to terminate the application.");
            Console.ReadLine();
        }
    }
}
like image 87
Gaurav Mantri Avatar answered Nov 05 '22 13:11

Gaurav Mantri