CAML Query Paging

13/07/2017 13:12
We needed to use paging in CAML query and this scenario is not supported, to query list with specific query and get e. g. third page of results.
I created two specific queries to list, one to get items count (query without rowlimit) and other empty query with rowlimit to return only appropriate PagingInfo object to get correct item set. 
 
camlQueryPaging.PagesInfo object is list of all pages to get item sets. Key is page number, Value is PagingInfo object for SharePoint CAML query
 
Then we can use following functions to get item set for specific page - defined by page number or PagingInfo object
 
camlQueryPaging.GetItemsForPageInfo
camlQueryPaging.GetItemsForPageNr
 
 
Separate class CamlQueryPaging was created and then called from SharePoint console application as following:
 
Program.cs
 
 
 
namespace SharepointConApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string siteUrl =  "https://server/sites/yoursiteurl";
            string webUrl = "";
                      
            using (SPSite site = new SPSite(siteUrl))
            {
                using (SPWeb web = site.OpenWeb(webUrl))
                {
              
                   var list = web.Lists["Documents"];
              
                    Console.WriteLine();
                    Console.WriteLine("==========================================");
                    Console.WriteLine("         CAML QUERY PAGING OBJECT");
                    Console.WriteLine("==========================================");
 
                    var query = "<Where></Where>";
 
                    //query = "<Where><Neq><FieldRef Name='File_x0020_Type'/><Value Type='Text'>txt</Value></Neq></Where>";
                    query = "<Where></Where><OrderBy><FieldRef Name='Modified' Ascending='FALSE' /></OrderBy>";
                    
                    var camlQueryPaging = new CamlQueryPaging(list, "Shared Documents", query, 10);
                    //var camlQueryPaging = new CamlQueryPaging(list, "Pages", query, 3);
                    //var camlQueryPaging = new CamlQueryPaging(list, "Picture library/My subfolder", query, 3);
                    
                    Console.WriteLine("{0}", query);
 
                    Console.WriteLine("ItemsCount: {0}", camlQueryPaging.ItemsCount);
                    Console.WriteLine("PageRowLimit: {0}", camlQueryPaging.PageRowLimit);
                    Console.WriteLine("PagesCount: {0}", camlQueryPaging.PagesCount);
                  
                    foreach (var page in camlQueryPaging.PagesInfo)
                    {
Console.WriteLine("{0}, {1}", page.Key, page.Value );
                    }
 
                    var pageNr = 4;
                    var pageItems1 = camlQueryPaging.GetItemsForPageNr(1);
                    RenderItemsForPage(pageItems1, 1);
 
                    var pageItems2 = camlQueryPaging.GetItemsForPageNr(2);
                    RenderItemsForPage(pageItems2, 2);
 
                    var pageItems3 = camlQueryPaging.GetItemsForPageNr(3);
                    RenderItemsForPage(pageItems3, 3);
 
                    var pageItems4 = camlQueryPaging.GetItemsForPageNr(4);
                    RenderItemsForPage(pageItems4, 4);
 
                    Console.WriteLine("=========== PAGEINFO Items ====================");
 
                    var page2Info = camlQueryPaging.PagesInfo[1].Value;
                    var pageinfoItems2 = camlQueryPaging.GetItemsForPageInfo(page2Info);
 
                    RenderItemsForPageInfo(pageinfoItems2, page2Info);
 
//Get subfolder items count by keeping query - call constructor without rowlimit parameter
                    var subFolderUrl = "Shared Documents/Upload";
                    var pngQuery = "<Where><In><FieldRef Name='File_x0020_Type' /><Values><Value Type='Text'>txt</Value><Value Type='Text'>jpg</Value></Values></In></Where>";
                    pngQuery = "<Where></Where>";
                    var camlQueryPaging2 = new CamlQueryPaging(list, subFolderUrl, pngQuery);
                    Console.WriteLine("{0} - items: {1}, query: {2}", subFolderUrl, camlQueryPaging2.ItemsCount, pngQuery);
                    
                }
                
            }
 
            Console.ReadLine();
        }
 
        public static void RenderItemsForPage(SPListItemCollection pageItems, int pageNr)
        {
            Console.WriteLine("SelectedPage: {0}", pageNr);
 
            if (pageItems != null)
            {
                Console.WriteLine("=========== Items for page {0} ===========", pageNr);
 
                foreach (SPListItem item in pageItems)
                {
                    var tags = GetTaxonomyFieldValues(item, "TeamTags");
                    Console.WriteLine("{0} - {1}, tags: {2}", item.ID, item["Name"], tags);
                }
            }
            else
            {
                Console.WriteLine("No items for page {0}", pageNr);
            }
        }
 
        public static void RenderItemsForPageInfo(SPListItemCollection pageItems, string pageInfo)
        {
            Console.WriteLine("SelectedPage: {0}", pageInfo);
 
            if (pageItems != null)
            {
                Console.WriteLine("=========== Items for page {0} ===========", pageInfo);
 
                foreach (SPListItem item in pageItems)
                {
                    var tags = GetTaxonomyFieldValues(item, "TeamTags");
                    Console.WriteLine("{0} - {1}, tags: {2}", item.ID, item["Name"], tags);
                }
            }
            else
            {
                Console.WriteLine("No items for page {0}", pageInfo);
            }
        }
}
}
 
CamlQueryPaging.cs
 
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SharepointConApp.Code
{
    class CamlQueryPaging
    {
        public int ItemsCount { get; set; }
        public int PageRowLimit { get; set; }
        public int PagesCount { get; set; }
        public int SelectedPage { get; set; }
        public List<KeyValuePair<int, string>> PagesInfo { get; set; }
 
        private static SPList _list;
        private static string _queryString;
        private static SPFolder _folder;
 
        public CamlQueryPaging(SPList list, string folderUrl, string queryString)
        {
            _list = list;
            _queryString = queryString;
 
            var web = list.ParentWeb;
            var folderServerRelativeUrl = SPUrlUtility.CombineUrl(web.Url, folderUrl);
            _folder = web.GetFolder(folderServerRelativeUrl);
 
            ItemsCount = GetListItemsCountInQuery();
            PagesCount = 1;
 
            SelectedPage = 1;
 
            int intIndex = 1;
 
            var query = new SPQuery();
            query.Query = queryString;
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
            query.Folder = _folder;
 
            PagesInfo = new List<KeyValuePair<int, string>>();
 
            PagesInfo.Add(new KeyValuePair<int, string>(intIndex, ""));
        }
 
        public CamlQueryPaging(SPList list, string folderUrl, string queryString, int rowLimit)
        {
            _list = list;
            _queryString = queryString;
 
            var web = list.ParentWeb;
            var folderServerRelativeUrl = SPUrlUtility.CombineUrl(web.Url, folderUrl);
            _folder = web.GetFolder(folderServerRelativeUrl);
 
            ItemsCount = GetListItemsCountInQuery();
            PageRowLimit = rowLimit;
            PagesCount = ItemsCount / PageRowLimit;
            if((ItemsCount % PageRowLimit) != 0)
                PagesCount++;
 
            SelectedPage = 1;
 
            int intIndex = 1;
 
            var query = new SPQuery() { RowLimit = (uint)rowLimit };;
            query.Query = queryString;
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
            query.Folder = _folder;
 
            PagesInfo = new List<KeyValuePair<int, string>>();
 
            PagesInfo.Add(new KeyValuePair<int, string>(intIndex, ""));
 
            do
            {
                SPListItemCollection items = list.GetItems(query);
               
                query.ListItemCollectionPosition =
                  items.ListItemCollectionPosition;
 
                if (query.ListItemCollectionPosition != null)
                {
                    PagesInfo.Add(new KeyValuePair<int, string>(intIndex + 1, query.ListItemCollectionPosition.PagingInfo));
                }
 
                intIndex++;
            } while (query.ListItemCollectionPosition != null);
 
        }
 
        private static int GetListItemsCountInQuery()
        {
            var query = new SPQuery();
            query.Query = _queryString;
            query.Folder = _folder;
 
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
 
            var items = _list.GetItems(query);
 
            return items.Count;
        }
 
        public SPListItemCollection GetItemsForPageNr(int pageNr)
        {
            if (pageNr > this.PagesInfo.Count)
                return null;
 
            this.SelectedPage = pageNr;
            var query = new SPQuery() { RowLimit = (uint)this.PageRowLimit };
 
            var pageInfo = this.PagesInfo.Where(p => p.Key == pageNr).FirstOrDefault().Value;
            var position = new SPListItemCollectionPosition(pageInfo);
 
            query.Query = _queryString;
            query.Folder = _folder;
            if (!string.IsNullOrEmpty(pageInfo))
                query.ListItemCollectionPosition = position;
 
            var items = _list.GetItems(query);
 
            return items;
        }
 
        public SPListItemCollection GetItemsForPageInfo(string pageInfo)
        {
            var query = new SPQuery() { RowLimit = (uint)this.PageRowLimit };
            var position = new SPListItemCollectionPosition(pageInfo);
 
            query.Query = _queryString;
            query.Folder = _folder;
            if (!string.IsNullOrEmpty(pageInfo))
                query.ListItemCollectionPosition = position;
 
            var items = _list.GetItems(query);
 
            var pageNr = this.PagesInfo.Where(p => p.Value == pageInfo).FirstOrDefault().Key;
            this.SelectedPage = pageNr;
 
            return items;
        }
    }
}
 
 
We needed to use paging in CAML query and this scenario is not supported, to query list with specific query and get e. g. third page of results.
I created two specific queries to list, one to get items count (query without rowlimit) and other empty query with rowlimit to return only appropriate PagingInfo object
to get correct item set. 
 
camlQueryPaging.PagesInfo object is list of all pages to get item sets. Key is page number, Value is PagingInfo object for SharePoint CAML query
 
Then we can use following functions to get item set for specific page - defined by page number or PagingInfo object
 
camlQueryPaging.GetItemsForPageInfo
camlQueryPaging.GetItemsForPageNr
 
 
Separate class CamlQueryPaging was created and then called in SharePoint console application as following:
 
namespace SharepointConApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string siteUrl =  "https://server/sites/yoursiteurl";
            string webUrl = "";
                      
            using (SPSite site = new SPSite(siteUrl))
            {
                using (SPWeb web = site.OpenWeb(webUrl))
                {
              
                   var list = web.Lists["Documents"];
              
                    Console.WriteLine();
                    Console.WriteLine("==========================================");
                    Console.WriteLine("         CAML QUERY PAGING OBJECT");
                    Console.WriteLine("==========================================");
 
                    var query = "<Where></Where>";
 
                    //query = "<Where><Neq><FieldRef Name='File_x0020_Type'/><Value Type='Text'>txt</Value></Neq></Where>";
                    query = "<Where></Where><OrderBy><FieldRef Name='Modified' Ascending='FALSE' /></OrderBy>";
                    
                    var camlQueryPaging = new CamlQueryPaging(list, "Shared Documents", query, 10);
                    //var camlQueryPaging = new CamlQueryPaging(list, "Pages", query, 3);
                    //var camlQueryPaging = new CamlQueryPaging(list, "Picture library/My subfolder", query, 3);
                    
                    Console.WriteLine("{0}", query);
 
                    Console.WriteLine("ItemsCount: {0}", camlQueryPaging.ItemsCount);
                    Console.WriteLine("PageRowLimit: {0}", camlQueryPaging.PageRowLimit);
                    Console.WriteLine("PagesCount: {0}", camlQueryPaging.PagesCount);
                  
                    foreach (var page in camlQueryPaging.PagesInfo)
                    {
Console.WriteLine("{0}, {1}", page.Key, page.Value );
                    }
 
                    var pageNr = 4;
                    var pageItems1 = camlQueryPaging.GetItemsForPageNr(1);
                    RenderItemsForPage(pageItems1, 1);
 
                    var pageItems2 = camlQueryPaging.GetItemsForPageNr(2);
                    RenderItemsForPage(pageItems2, 2);
 
                    var pageItems3 = camlQueryPaging.GetItemsForPageNr(3);
                    RenderItemsForPage(pageItems3, 3);
 
                    var pageItems4 = camlQueryPaging.GetItemsForPageNr(4);
                    RenderItemsForPage(pageItems4, 4);
 
                    Console.WriteLine("=========== PAGEINFO Items ====================");
 
                    var page2Info = camlQueryPaging.PagesInfo[1].Value;
                    var pageinfoItems2 = camlQueryPaging.GetItemsForPageInfo(page2Info);
 
                    RenderItemsForPageInfo(pageinfoItems2, page2Info);
 
//Get subfolder items count by keeping query - call constructor without rowlimit parameter
                    var subFolderUrl = "Shared Documents/Upload";
                    var pngQuery = "<Where><In><FieldRef Name='File_x0020_Type' /><Values><Value Type='Text'>txt</Value><Value Type='Text'>jpg</Value></Values></In></Where>";
                    pngQuery = "<Where></Where>";
                    var camlQueryPaging2 = new CamlQueryPaging(list, subFolderUrl, pngQuery);
                    Console.WriteLine("{0} - items: {1}, query: {2}", subFolderUrl, camlQueryPaging2.ItemsCount, pngQuery);
                    
                }
                
            }
 
            Console.ReadLine();
        }
 
        public static void RenderItemsForPage(SPListItemCollection pageItems, int pageNr)
        {
            Console.WriteLine("SelectedPage: {0}", pageNr);
 
            if (pageItems != null)
            {
                Console.WriteLine("=========== Items for page {0} ===========", pageNr);
 
                foreach (SPListItem item in pageItems)
                {
                    var tags = GetTaxonomyFieldValues(item, "TeamTags");
                    Console.WriteLine("{0} - {1}, tags: {2}", item.ID, item["Name"], tags);
                }
            }
            else
            {
                Console.WriteLine("No items for page {0}", pageNr);
            }
        }
 
        public static void RenderItemsForPageInfo(SPListItemCollection pageItems, string pageInfo)
        {
            Console.WriteLine("SelectedPage: {0}", pageInfo);
 
            if (pageItems != null)
            {
                Console.WriteLine("=========== Items for page {0} ===========", pageInfo);
 
                foreach (SPListItem item in pageItems)
                {
                    var tags = GetTaxonomyFieldValues(item, "TeamTags");
                    Console.WriteLine("{0} - {1}, tags: {2}", item.ID, item["Name"], tags);
                }
            }
            else
            {
                Console.WriteLine("No items for page {0}", pageInfo);
            }
        }
}
}
 
CamlQueryPaging.cs
 
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SharepointConApp.Code
{
    class CamlQueryPaging
    {
        public int ItemsCount { get; set; }
        public int PageRowLimit { get; set; }
        public int PagesCount { get; set; }
        public int SelectedPage { get; set; }
        public List<KeyValuePair<int, string>> PagesInfo { get; set; }
 
        private static SPList _list;
        private static string _queryString;
        private static SPFolder _folder;
 
        public CamlQueryPaging(SPList list, string folderUrl, string queryString)
        {
            _list = list;
            _queryString = queryString;
 
            var web = list.ParentWeb;
            var folderServerRelativeUrl = SPUrlUtility.CombineUrl(web.Url, folderUrl);
            _folder = web.GetFolder(folderServerRelativeUrl);
 
            ItemsCount = GetListItemsCountInQuery();
            PagesCount = 1;
 
            SelectedPage = 1;
 
            int intIndex = 1;
 
            var query = new SPQuery();
            query.Query = queryString;
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
            query.Folder = _folder;
 
            PagesInfo = new List<KeyValuePair<int, string>>();
 
            PagesInfo.Add(new KeyValuePair<int, string>(intIndex, ""));
        }
 
        public CamlQueryPaging(SPList list, string folderUrl, string queryString, int rowLimit)
        {
            _list = list;
            _queryString = queryString;
 
            var web = list.ParentWeb;
            var folderServerRelativeUrl = SPUrlUtility.CombineUrl(web.Url, folderUrl);
            _folder = web.GetFolder(folderServerRelativeUrl);
 
            ItemsCount = GetListItemsCountInQuery();
            PageRowLimit = rowLimit;
            PagesCount = ItemsCount / PageRowLimit;
            if((ItemsCount % PageRowLimit) != 0)
                PagesCount++;
 
            SelectedPage = 1;
 
            int intIndex = 1;
 
            var query = new SPQuery() { RowLimit = (uint)rowLimit };;
            query.Query = queryString;
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
            query.Folder = _folder;
 
            PagesInfo = new List<KeyValuePair<int, string>>();
 
            PagesInfo.Add(new KeyValuePair<int, string>(intIndex, ""));
 
            do
            {
                SPListItemCollection items = list.GetItems(query);
               
                query.ListItemCollectionPosition =
                  items.ListItemCollectionPosition;
 
                if (query.ListItemCollectionPosition != null)
                {
                    PagesInfo.Add(new KeyValuePair<int, string>(intIndex + 1, query.ListItemCollectionPosition.PagingInfo));
                }
 
                intIndex++;
            } while (query.ListItemCollectionPosition != null);
 
        }
 
        private static int GetListItemsCountInQuery()
        {
            var query = new SPQuery();
            query.Query = _queryString;
            query.Folder = _folder;
 
            query.ViewFields = "<ViewFields></ViewFields>";
            query.ViewFieldsOnly = true;
 
            var items = _list.GetItems(query);
 
            return items.Count;
        }
 
        public SPListItemCollection GetItemsForPageNr(int pageNr)
        {
            if (pageNr > this.PagesInfo.Count)
                return null;
 
            this.SelectedPage = pageNr;
            var query = new SPQuery() { RowLimit = (uint)this.PageRowLimit };
 
            var pageInfo = this.PagesInfo.Where(p => p.Key == pageNr).FirstOrDefault().Value;
            var position = new SPListItemCollectionPosition(pageInfo);
 
            query.Query = _queryString;
            query.Folder = _folder;
            if (!string.IsNullOrEmpty(pageInfo))
                query.ListItemCollectionPosition = position;
 
            var items = _list.GetItems(query);
 
            return items;
        }
 
        public SPListItemCollection GetItemsForPageInfo(string pageInfo)
        {
            var query = new SPQuery() { RowLimit = (uint)this.PageRowLimit };
            var position = new SPListItemCollectionPosition(pageInfo);
 
            query.Query = _queryString;
            query.Folder = _folder;
            if (!string.IsNullOrEmpty(pageInfo))
                query.ListItemCollectionPosition = position;
 
            var items = _list.GetItems(query);
 
            var pageNr = this.PagesInfo.Where(p => p.Value == pageInfo).FirstOrDefault().Key;
            this.SelectedPage = pageNr;
 
            return items;
        }
    }
}