понедельник, 20 августа 2012 г.

Разбиение запроса SPQuery на страницы

Ещё один способ получить большое количество данных – это использовать разбиение запроса на страницы, т.е. получение элементов списка порциями по несколько элементов.

Для этого надо указать объекту класса SPQuery значения для свойств ListItemCollectionPosition и RowLimit.

RowLimit – указывает сколько элементов списка необходимо получить.

Свойство ListItemCollectionPosition – это объект класса SPListItemCollectionPosition принимающий в конструкторе строковой параметр, в котором указано с какого элемента необходимо получить данные (точнее следующего за ним элемента). Выглядит это так: “Paged=TRUE&p_ID=5” – получить элементы после элемента с ID равным 5.

Например, сделаем такой метод:

private static SPListItemCollection GetPagedItems(SPList list, string pagingInfo, uint rowLimit)
{

            var query = new SPQuery
                {
                    RowLimit = rowLimit,
                    ListItemCollectionPosition = new SPListItemCollectionPosition(pagingInfo)
                };
                    
            return list.GetItems(query);
}

 

Метод возвращает заданное количество элементов (rowLimit) из указанной страницы (pagintInfo).

Если в pagingInfo передавать пустую строку, то метод вернёт первую страницу.

Возвращаемые методом данные (типа SPListItemCollection) содержат в себе данные для получения следующей страницы – свойство ListItemCollectionPosition.

 

Таким образом, мы можем организовать постраничную загрузку и обработку элементов списка, например следующим образом (используя вышеприведённый метод):

using (var site = new SPSite("http://mysite/"))
{
    using (var web = site.OpenWeb())
    {
        var list = web.Lists["TestList"];

        var pagingInfo = string.Empty; //Здесь храним информацию о странице
        var pageNumber = 1; //Номер страницы, для оформления вывода
        SPListItemCollection items = null; //Полученные данные

        do
        {
            if (items != null && items.ListItemCollectionPosition != null)
                pagingInfo = items.ListItemCollectionPosition.PagingInfo; //Получаем данные о странице из предыдущего запроса

            Console.WriteLine("Page {0}, Info '{1}'", pageNumber, pagingInfo);

            items = GetPagedItems(list, pagingInfo, 5); //Получаем по 5 элементов
            foreach (SPListItem item in items)
                Console.WriteLine(item.Title);

            Console.WriteLine();
            pageNumber++;
        } while (items.ListItemCollectionPosition != null);
    }
}

 

Для моего списка результат выглядит следующим образом (консольное приложение):

image

10 комментариев:

  1. Вот сколько писал код для SP - почти ни разу не потребовалось использовать paging в коде. Даже ContentIterator очень редко использовал.

    Может есть примеры как сделать какое-либо полезное решение с этим кодом?

    ОтветитьУдалить
    Ответы
    1. Мне пришлось использовать пейджинг при аггрегации нескольких списков в JsGrid.

      А развертывание пейджинга (т.е. последовательное получение всех элементов с помощью пейджинга) требовалось при выгрузке этого аггрегированного представления в Excel.

      Так что задачи потенциально есть. Но редко.

      Удалить
    2. Я сам никогда не пользовался - ни ContentIterator, ни разбиением SPQuery на страницы.
      Но думаю задачи всё равно у кого-нибудь найдутся, так пусть он найдёт ответ хотя бы тут! :)

      Удалить
  2. Опять же, чтобы обойти SPQueryThrottleException, когда получаем очень много элементов.
    Других примеров применения думаю не будет.
    Разве что, когда отображаем только определённую страницу элементов, но тут нужно ещё поизвращаться, чтобы найти ID последнего элемента на предыдущей странице.

    ОтветитьУдалить
  3. Вот тоже грешен, ContentIterator - вообще не использовал , а вот с педженгом возится приходилось, но давно. Но вот я опой чую что всю выборку надо делать через ContentIterator + paging , так сказать патерн разработать и юзать его везде и всегда, что бы спалось по ночам хорошо и не переживать что у тебя в решении SPQueryThrottleException вылетит :)

    ОтветитьУдалить
    Ответы
    1. Кстати да, а то х/з когда у них там за 5 тыщ элементов перевалит... :)
      Меня может рядом уже не оказаться...

      Удалить
  4. > Опять же, чтобы обойти SPQueryThrottleException, когда получаем очень много элементов.

    А зачем получать "очень много элементов"?

    ОтветитьУдалить
    Ответы
    1. Разные задачи же могут быть...
      Например, передача их куда-нибудь, или построение отчёта по ним.

      Удалить
    2. Проще писать в базу в момент изменения, чем использовать paging.

      Удалить
    3. Причём тут писать в базу, если нам данные вытащить надо!

      Удалить